cargo vendor
This commit is contained in:
parent
81bc331357
commit
af18754224
5
.cargo/config.toml
Normal file
5
.cargo/config.toml
Normal file
@ -0,0 +1,5 @@
|
||||
[source.crates-io]
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source.vendored-sources]
|
||||
directory = "vendor"
|
53
Cargo.lock
generated
Normal file
53
Cargo.lock
generated
Normal file
@ -0,0 +1,53 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "apt-pkg-native"
|
||||
version = "0.3.2"
|
||||
dependencies = [
|
||||
"boolinator",
|
||||
"cc",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "boolinator"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
1
vendor/boolinator/.cargo-checksum.json
vendored
Normal file
1
vendor/boolinator/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"40444b7bc44b1df1026d48095d31a60bc2fc6ac1521459e28096b1e936f895fb","LICENSE":"a030e8c6eaabd94e4cfd2ef01e895a67a44ffca3139e67adcb553d988d390bdd","README.md":"7d7fa218e292c550f29861399337290bd14a13254a4201ce3d22077f68d343e9","src/lib.rs":"588297dd1280298b942b3679a2eeb3a4befd35853577d8f99dd3bb1935b207ca"},"package":"cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"}
|
19
vendor/boolinator/Cargo.toml
vendored
Normal file
19
vendor/boolinator/Cargo.toml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "boolinator"
|
||||
version = "2.4.0"
|
||||
authors = ["Daniel Keep <daniel.keep@gmail.com>"]
|
||||
|
||||
description = "Provides the Boolinator trait, which lets you use Option and Result-style combinators with bools."
|
||||
repository = "https://github.com/DanielKeep/rust-boolinator"
|
||||
documentation = "https://danielkeep.github.io/rust-boolinator/doc/boolinator/index.html"
|
||||
readme = "README.md"
|
||||
keywords = ["bool", "combinator", "monad", "serious"]
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
exclude = [
|
||||
".gitignore",
|
||||
".gitmodules",
|
||||
".travis.yml",
|
||||
"appveyor.yml",
|
||||
"scripts/*",
|
||||
]
|
237
vendor/boolinator/LICENSE
vendored
Normal file
237
vendor/boolinator/LICENSE
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
Copyright ⓒ 2016 Daniel Keep.
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
* MIT license, or
|
||||
* Apache License, Version 2.0
|
||||
|
||||
at your option.
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally
|
||||
submitted for inclusion in the work by you shall be dual licensed as
|
||||
above, without any additional terms or conditions.
|
||||
|
||||
# MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# Apache License, Version 2.0
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
26
vendor/boolinator/README.md
vendored
Normal file
26
vendor/boolinator/README.md
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# `boolinator`
|
||||
|
||||
Provides the `Boolinator` trait, which lets you use `Option` and `Result`-style combinators with `bool`s.
|
||||
|
||||
**Links**
|
||||
|
||||
* [Latest Release](https://crates.io/crates/boolinator/)
|
||||
* [Latest Docs](https://danielkeep.github.io/rust-boolinator/doc/boolinator/index.html)
|
||||
* [Repository](https://github.com/DanielKeep/rust-boolinator)
|
||||
|
||||
## Compatibility
|
||||
|
||||
`boolinator` is tested against Rust 1.0+. *Exhaustively* so.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* MIT license (see [LICENSE](LICENSE) or <http://opensource.org/licenses/MIT>)
|
||||
* Apache License, Version 2.0 (see [LICENSE](LICENSE) or <http://www.apache.org/licenses/LICENSE-2.0>)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.
|
260
vendor/boolinator/src/lib.rs
vendored
Normal file
260
vendor/boolinator/src/lib.rs
vendored
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
Copyright ⓒ 2016 Daniel Keep.
|
||||
|
||||
Licensed under the MIT license (see LICENSE or <http://opensource.org
|
||||
/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
|
||||
<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
|
||||
files in the project carrying such notice may not be copied, modified,
|
||||
or distributed except according to those terms.
|
||||
*/
|
||||
/*!
|
||||
|
||||
Provides the [`Boolinator`](trait.Boolinator.html) trait, which lets you use `Option` and `Result`-style combinators with `bool`s.
|
||||
|
||||
<style type="text/css">
|
||||
.link-block { font-family: "Fira Sans"; }
|
||||
.link-block > p { display: inline-block; }
|
||||
.link-block > p > strong { font-weight: 500; margin-right: 1em; }
|
||||
.link-block > ul { display: inline-block; padding: 0; list-style: none; }
|
||||
.link-block > ul > li {
|
||||
font-size: 0.8em;
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
padding: 0.3em;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
<span></span><div class="link-block">
|
||||
|
||||
**Links**
|
||||
|
||||
* [Latest Release](https://crates.io/crates/boolinator/)
|
||||
* [Latest Docs](https://danielkeep.github.io/rust-boolinator/doc/boolinator/index.html)
|
||||
* [Repository](https://github.com/DanielKeep/rust-boolinator)
|
||||
|
||||
<span></span></div>
|
||||
|
||||
## Compatibility
|
||||
|
||||
`boolinator` is tested against Rust 1.0+. *Exhaustively* so.
|
||||
|
||||
*/
|
||||
// Can't have undocumented APIs! Nosiree!
|
||||
#![deny(missing_docs)]
|
||||
|
||||
/**
|
||||
This trait defines a number of combinator-style methods for use with `bool` values.
|
||||
|
||||
In general, `true`/`false` map to `Some(_)`/`None` and `Ok(_)`/`Err(_)` respectively.
|
||||
*/
|
||||
pub trait Boolinator: Sized {
|
||||
/**
|
||||
If this value is `true`, returns `Some(())`; `None` otherwise.
|
||||
*/
|
||||
fn as_option(self) -> Option<()>;
|
||||
|
||||
/**
|
||||
If this value is `true`, returns `Some(some)`; `None` otherwise.
|
||||
*/
|
||||
fn as_some<T>(self, some: T) -> Option<T>;
|
||||
|
||||
/**
|
||||
If this value is `true`, returns `Some(some())`; `None` otherwise.
|
||||
*/
|
||||
fn as_some_from<T, F>(self, some: F) -> Option<T>
|
||||
where F: FnOnce() -> T;
|
||||
|
||||
/**
|
||||
If this value is `true`, returns `opt`; `None` otherwise.
|
||||
*/
|
||||
fn and_option<T>(self, opt: Option<T>) -> Option<T>;
|
||||
|
||||
/**
|
||||
If this value is `true`, returns `opt()`; `None` otherwise.
|
||||
*/
|
||||
fn and_option_from<T, F>(self, opt: F) -> Option<T>
|
||||
where F: FnOnce() -> Option<T>;
|
||||
|
||||
/**
|
||||
If this value is `true`, returns `Ok(ok)`; `Err(err)` otherwise.
|
||||
*/
|
||||
fn as_result<T, E>(self, ok: T, err: E) -> Result<T, E>;
|
||||
|
||||
/**
|
||||
If this value is `true`, returns `Ok(ok())`; `Err(err())` otherwise.
|
||||
*/
|
||||
fn as_result_from<T, E, F, G>(self, ok: F, err: G) -> Result<T, E>
|
||||
where F: FnOnce() -> T, G: FnOnce() -> E;
|
||||
|
||||
/**
|
||||
If this value is `true`, returns `Ok(())`; `Err(err)` otherwise.
|
||||
*/
|
||||
fn ok_or<E>(self, err: E) -> Result<(), E>;
|
||||
|
||||
/**
|
||||
If this value is `true`, returns `Ok(())`; `Err(err())` otherwise.
|
||||
*/
|
||||
fn ok_or_else<E, G>(self, err: G) -> Result<(), E>
|
||||
where G: FnOnce() -> E;
|
||||
|
||||
/**
|
||||
If this value is `true`, panics with `msg`; does nothing otherwise.
|
||||
*/
|
||||
fn expect(self, msg: &str);
|
||||
}
|
||||
|
||||
impl Boolinator for bool {
|
||||
#[inline]
|
||||
fn as_option(self) -> Option<()> {
|
||||
if self { Some(()) } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_some<T>(self, some: T) -> Option<T> {
|
||||
if self { Some(some) } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_some_from<T, F>(self, some: F) -> Option<T>
|
||||
where F: FnOnce() -> T {
|
||||
if self { Some(some()) } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn and_option<T>(self, opt: Option<T>) -> Option<T> {
|
||||
if self { opt } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn and_option_from<T, F>(self, opt: F) -> Option<T>
|
||||
where F: FnOnce() -> Option<T> {
|
||||
if self { opt() } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_result<T, E>(self, ok: T, err: E) -> Result<T, E> {
|
||||
if self { Ok(ok) } else { Err(err) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_result_from<T, E, F, G>(self, ok: F, err: G) -> Result<T, E>
|
||||
where F: FnOnce() -> T, G: FnOnce() -> E {
|
||||
if self { Ok(ok()) } else { Err(err()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ok_or<E>(self, err: E) -> Result<(), E> {
|
||||
if self { Ok(()) } else { Err(err) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ok_or_else<E, G>(self, err: G) -> Result<(), E>
|
||||
where G: FnOnce() -> E {
|
||||
if self { Ok(()) } else { Err(err()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn expect(self, msg: &str) {
|
||||
if self { () } else { panic!("{}", msg) }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Serious code must have serious tests, and Boolinator is serious business!
|
||||
*/
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Boolinator; // as opposed to the original NES version.
|
||||
|
||||
#[test]
|
||||
fn test_as_option() {
|
||||
// Very test.
|
||||
assert_eq!(true.as_option(), Some(()));
|
||||
assert_eq!(false.as_option(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_some() {
|
||||
// Much serious.
|
||||
let love = true;
|
||||
let everybody = love.as_some("body").expect("needs");
|
||||
assert_eq!(everybody, "body");
|
||||
|
||||
assert_eq!((!love).as_some("money can buy"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_some_from() {
|
||||
// Wow.
|
||||
let mothers = vec![true, false, false, true, false, true];
|
||||
assert!(mothers.into_iter()
|
||||
.map(|e| e.as_some_from(|| Some("em")))
|
||||
.filter(Option::is_some)
|
||||
.count() > 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_and_option() {
|
||||
// Such original.
|
||||
assert_eq!(true.and_option(Some("fries with that")), Some("fries with that"));
|
||||
assert_eq!(false.and_option(Some("fries with that")), None);
|
||||
assert_eq!(true.and_option(None), None::<()>);
|
||||
assert_eq!(false.and_option(None), None::<()>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_and_option_from() {
|
||||
// Such original.
|
||||
assert_eq!(true.and_option_from(|| Some("chips too, guv'")), Some("chips too, guv'"));
|
||||
assert_eq!(false.and_option_from(|| Some("chips too, guv'")), None);
|
||||
assert_eq!(true.and_option_from(|| None), None::<()>);
|
||||
assert_eq!(false.and_option_from(|| None), None::<()>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_result() {
|
||||
// Very result.
|
||||
assert_eq!(true.as_result("now; ", ", what?"), Ok("now; "));
|
||||
assert_eq!(false.as_result("now; ", ", what?"), Err(", what?"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_result_from() {
|
||||
// Code good.
|
||||
assert_eq!(true.as_result_from(|| "four space indent", || "anything else"), Ok("four space indent"));
|
||||
assert_eq!(false.as_result_from(|| "four space indent", || "anything else"), Err("anything else"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ok_or() {
|
||||
// Ok.
|
||||
let mut annie = true;
|
||||
assert_eq!(annie.ok_or("hit back"), Ok(()));
|
||||
annie = false;
|
||||
assert_eq!(annie.ok_or("hit back"), Err("hit back"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ok_or_else() {
|
||||
// Ok.
|
||||
let mut annie = true;
|
||||
assert_eq!(annie.ok_or_else(|| "hit back"), Ok(()));
|
||||
annie = false;
|
||||
assert_eq!(annie.ok_or_else(|| "hit back"), Err("hit back"));
|
||||
}
|
||||
|
||||
const DREAMS: &'static str = "love and financial security";
|
||||
|
||||
#[test]
|
||||
fn test_expect() {
|
||||
// Movies lie.
|
||||
true.expect(DREAMS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_expect_reality() {
|
||||
// Send hugs.
|
||||
false.expect(DREAMS);
|
||||
}
|
||||
}
|
1
vendor/cc/.cargo-checksum.json
vendored
Normal file
1
vendor/cc/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"CHANGELOG.md":"b09b2c41f72a4a7653608cb7d042d350b213af844dd231bf5ede36c04241a47c","Cargo.toml":"adad9689626fbf42c9807176a5fc1a20e8e95c7777b96d72ce1383ceb4e0c670","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"f1ddbede208a5b78333a25dac0a7598e678e9b601a7d99a791069bddaf180dfe","clippy.toml":"2a564c2c1e9a9c46e2b667d0b9574e2fda233e3c26dffbcd55373d052f042905","src/command_helpers.rs":"7c09d713b9a7ad45ad4fc431206681819465b871e7408573b311e300b1e9e21c","src/detect_compiler_family.c":"72903b91d7a28f49b39e7d730f4c9c4bb39fb901948fa1279cd08abf392f5a29","src/lib.rs":"3213e05f797701c9da797509512991e18a40455b1d9478531640f90d1f13134e","src/parallel/async_executor.rs":"4ce24435fff6b6555b43fee042c16bd65d4150d0346567f246b9190d85b45983","src/parallel/job_token.rs":"8ef38688fdf867606a32500078094e0bb22fb2aec9ae11a392593bbfc101ed4f","src/parallel/mod.rs":"bd9c1334d17d138c281961c690b8d8118a2d6295a7d6cd7296826255436fa063","src/parallel/stderr.rs":"a2d18ba3f2e04deb9047ece9ab7ca5452d9a76b515afbe20a76307e31597f34b","src/target_info.rs":"342be00f6215e161d8163e272a2945bb9f52f171648e15e11d46800a73186955","src/tempfile.rs":"b12a0821586ab3945fe4ff574cd76699c3694a103dbf1b5764fd1fbcbbd7c37e","src/tool.rs":"24291f79784a990602e2244ccf965127088e43bd58745a3829d0d06dddd588b6","src/utilities.rs":"a13bb0a351fcef72823485b1b5dc4f514c533fa4feac95deb66ed9e5fbfe7b53","src/windows/com.rs":"a2800ddb81215fff2bf618336f5c4ff8e8bdb746dd18b795873c7304b3f2a5e3","src/windows/find_tools.rs":"8eb56f4af6cc40b943e25dba9f26d1629c0c464b2839a6c5aa8d3f0b973a649c","src/windows/mod.rs":"42f1ad7fee35a17686b003e6aa520d3d1940d47d2f531d626e9ae0c48ba49005","src/windows/registry.rs":"c521b72c825e8095843e73482ffa810ed066ad8bb9f86e6db0c5c143c171aba1","src/windows/setup_config.rs":"754439cbab492afd44c9755abcbec1a41c9b2c358131cee2df13c0e996dbbec8","src/windows/vs_instances.rs":"946527cf8fd32c3472f6a2884dcdec290763101097334c7478f9c24c3950db6b","src/windows/winapi.rs":"250d51c1826d1a2329e9889dd9f058cfce253dbf2a678b076147c6cdb5db046c","src/windows/windows_sys.rs":"da77f89b4a47122dd06d5e8627c96e9f4406944e25e4ca83dc7058ba31d716e3"},"package":"74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490"}
|
46
vendor/cc/CHANGELOG.md
vendored
Normal file
46
vendor/cc/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.0.104](https://github.com/rust-lang/cc-rs/compare/cc-v1.0.103...cc-v1.0.104) - 2024-07-01
|
||||
|
||||
### Other
|
||||
- Fixed link break about compile-time-requirements ([#1118](https://github.com/rust-lang/cc-rs/pull/1118))
|
||||
|
||||
## [1.0.103](https://github.com/rust-lang/cc-rs/compare/cc-v1.0.102...cc-v1.0.103) - 2024-06-30
|
||||
|
||||
### Other
|
||||
- Fix compilation for wasm: env WASI_SYSROOT should be optional ([#1114](https://github.com/rust-lang/cc-rs/pull/1114))
|
||||
|
||||
## [1.0.102](https://github.com/rust-lang/cc-rs/compare/cc-v1.0.101...cc-v1.0.102) - 2024-06-29
|
||||
|
||||
### Other
|
||||
- Fix invalid wasi targets compatibility ([#1105](https://github.com/rust-lang/cc-rs/pull/1105))
|
||||
- Speedup regenerate-target-info and regenerate-windows-sys ([#1110](https://github.com/rust-lang/cc-rs/pull/1110))
|
||||
|
||||
## [1.0.101](https://github.com/rust-lang/cc-rs/compare/cc-v1.0.100...cc-v1.0.101) - 2024-06-25
|
||||
|
||||
### Other
|
||||
- Use `Build::getenv` instead of `env::var*` in anywhere that makes sense ([#1103](https://github.com/rust-lang/cc-rs/pull/1103))
|
||||
|
||||
## [1.0.100](https://github.com/rust-lang/cc-rs/compare/cc-v1.0.99...cc-v1.0.100) - 2024-06-23
|
||||
|
||||
### Other
|
||||
- Update publish.yml to use release-plz ([#1101](https://github.com/rust-lang/cc-rs/pull/1101))
|
||||
- Accpet `OsStr` instead of `str` for flags ([#1100](https://github.com/rust-lang/cc-rs/pull/1100))
|
||||
- Use `dep:` syntax to avoid implicit features. ([#1099](https://github.com/rust-lang/cc-rs/pull/1099))
|
||||
- Minor clippy fixes. ([#1098](https://github.com/rust-lang/cc-rs/pull/1098))
|
||||
- Fix WASI compilation for C++ ([#1083](https://github.com/rust-lang/cc-rs/pull/1083))
|
||||
- Regenerate windows sys bindings ([#1096](https://github.com/rust-lang/cc-rs/pull/1096))
|
||||
- Rename regenerate-windows-sys to regenerate-windows-sys.yml ([#1095](https://github.com/rust-lang/cc-rs/pull/1095))
|
||||
- Create regenerate-windows-sys.yml ([#1094](https://github.com/rust-lang/cc-rs/pull/1094))
|
||||
- Update windows-bindgen requirement from 0.56 to 0.57 ([#1091](https://github.com/rust-lang/cc-rs/pull/1091))
|
||||
- Eagerly close tempfile to fix [#1082](https://github.com/rust-lang/cc-rs/pull/1082) ([#1087](https://github.com/rust-lang/cc-rs/pull/1087))
|
||||
- Output msvc.exe in the output directory ([#1090](https://github.com/rust-lang/cc-rs/pull/1090))
|
||||
- Fix clippy warnings on Windows ([#1088](https://github.com/rust-lang/cc-rs/pull/1088))
|
||||
- Don't try to free DLL on drop ([#1089](https://github.com/rust-lang/cc-rs/pull/1089))
|
||||
- Fix panic safety issue in StderrForwarder ([#1079](https://github.com/rust-lang/cc-rs/pull/1079))
|
58
vendor/cc/Cargo.toml
vendored
Normal file
58
vendor/cc/Cargo.toml
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
rust-version = "1.63"
|
||||
name = "cc"
|
||||
version = "1.0.104"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
exclude = [
|
||||
"/.github",
|
||||
"tests",
|
||||
"src/bin",
|
||||
]
|
||||
description = """
|
||||
A build-time dependency for Cargo build scripts to assist in invoking the native
|
||||
C compiler to compile native C code into a static archive to be linked into Rust
|
||||
code.
|
||||
"""
|
||||
homepage = "https://github.com/rust-lang/cc-rs"
|
||||
documentation = "https://docs.rs/cc"
|
||||
readme = "README.md"
|
||||
keywords = ["build-dependencies"]
|
||||
categories = ["development-tools::build-utils"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-lang/cc-rs"
|
||||
|
||||
[dependencies.jobserver]
|
||||
version = "0.1.30"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.once_cell]
|
||||
version = "1.19"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.tempfile]
|
||||
version = "3"
|
||||
|
||||
[features]
|
||||
parallel = [
|
||||
"dep:libc",
|
||||
"dep:jobserver",
|
||||
"dep:once_cell",
|
||||
]
|
||||
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2.62"
|
||||
optional = true
|
||||
default-features = false
|
201
vendor/cc/LICENSE-APACHE
vendored
Normal file
201
vendor/cc/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
25
vendor/cc/LICENSE-MIT
vendored
Normal file
25
vendor/cc/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
Copyright (c) 2014 Alex Crichton
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
27
vendor/cc/README.md
vendored
Normal file
27
vendor/cc/README.md
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# cc-rs
|
||||
|
||||
A library for [Cargo build scripts](https://doc.rust-lang.org/cargo/reference/build-scripts.html)
|
||||
to compile a set of C/C++/assembly/CUDA files into a static archive for Cargo
|
||||
to link into the crate being built. This crate does not compile code itself;
|
||||
it calls out to the default compiler for the platform. This crate will
|
||||
automatically detect situations such as cross compilation and
|
||||
various environment variables and will build code appropriately.
|
||||
|
||||
Refer to the [documentation](https://docs.rs/cc) for detailed usage instructions.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
https://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
https://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in cc-rs by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
4
vendor/cc/clippy.toml
vendored
Normal file
4
vendor/cc/clippy.toml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
disallowed-methods = [
|
||||
{ path = "std::env::var_os", reason = "Please use Build::getenv" },
|
||||
{ path = "std::env::var", reason = "Please use Build::getenv" },
|
||||
]
|
456
vendor/cc/src/command_helpers.rs
vendored
Normal file
456
vendor/cc/src/command_helpers.rs
vendored
Normal file
@ -0,0 +1,456 @@
|
||||
//! Miscellaneous helpers for running commands
|
||||
|
||||
use std::{
|
||||
collections::hash_map,
|
||||
ffi::OsString,
|
||||
fmt::Display,
|
||||
fs,
|
||||
hash::Hasher,
|
||||
io::{self, Read, Write},
|
||||
path::Path,
|
||||
process::{Child, ChildStderr, Command, Stdio},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{Error, ErrorKind, Object};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct CargoOutput {
|
||||
pub(crate) metadata: bool,
|
||||
pub(crate) warnings: bool,
|
||||
pub(crate) debug: bool,
|
||||
checked_dbg_var: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl CargoOutput {
|
||||
pub(crate) fn new() -> Self {
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
Self {
|
||||
metadata: true,
|
||||
warnings: true,
|
||||
debug: std::env::var_os("CC_ENABLE_DEBUG_OUTPUT").is_some(),
|
||||
checked_dbg_var: Arc::new(AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_metadata(&self, s: &dyn Display) {
|
||||
if self.metadata {
|
||||
println!("{}", s);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_warning(&self, arg: &dyn Display) {
|
||||
if self.warnings {
|
||||
println!("cargo:warning={}", arg);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_debug(&self, arg: &dyn Display) {
|
||||
if self.metadata && !self.checked_dbg_var.load(Ordering::Relaxed) {
|
||||
self.checked_dbg_var.store(true, Ordering::Relaxed);
|
||||
println!("cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT");
|
||||
}
|
||||
if self.debug {
|
||||
println!("{}", arg);
|
||||
}
|
||||
}
|
||||
|
||||
fn stdio_for_warnings(&self) -> Stdio {
|
||||
if self.warnings {
|
||||
Stdio::piped()
|
||||
} else {
|
||||
Stdio::null()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct StderrForwarder {
|
||||
inner: Option<(ChildStderr, Vec<u8>)>,
|
||||
#[cfg(feature = "parallel")]
|
||||
is_non_blocking: bool,
|
||||
#[cfg(feature = "parallel")]
|
||||
bytes_available_failed: bool,
|
||||
}
|
||||
|
||||
const MIN_BUFFER_CAPACITY: usize = 100;
|
||||
|
||||
impl StderrForwarder {
|
||||
pub(crate) fn new(child: &mut Child) -> Self {
|
||||
Self {
|
||||
inner: child
|
||||
.stderr
|
||||
.take()
|
||||
.map(|stderr| (stderr, Vec::with_capacity(MIN_BUFFER_CAPACITY))),
|
||||
#[cfg(feature = "parallel")]
|
||||
is_non_blocking: false,
|
||||
#[cfg(feature = "parallel")]
|
||||
bytes_available_failed: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn forward_available(&mut self) -> bool {
|
||||
if let Some((stderr, buffer)) = self.inner.as_mut() {
|
||||
loop {
|
||||
let old_data_end = buffer.len();
|
||||
|
||||
// For non-blocking we check to see if there is data available, so we should try to
|
||||
// read at least that much. For blocking, always read at least the minimum amount.
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
let to_reserve = MIN_BUFFER_CAPACITY;
|
||||
#[cfg(feature = "parallel")]
|
||||
let to_reserve = if self.is_non_blocking && !self.bytes_available_failed {
|
||||
match crate::parallel::stderr::bytes_available(stderr) {
|
||||
#[cfg(windows)]
|
||||
Ok(0) => break false,
|
||||
#[cfg(unix)]
|
||||
Ok(0) => {
|
||||
// On Unix, depending on the implementation, we may sometimes get 0 in a
|
||||
// loop (either there is data available or the pipe is broken), so
|
||||
// continue with the non-blocking read anyway.
|
||||
MIN_BUFFER_CAPACITY
|
||||
}
|
||||
#[cfg(windows)]
|
||||
Err(_) => {
|
||||
// On Windows, if we get an error then the pipe is broken, so flush
|
||||
// the buffer and bail.
|
||||
if !buffer.is_empty() {
|
||||
write_warning(&buffer[..]);
|
||||
}
|
||||
self.inner = None;
|
||||
break true;
|
||||
}
|
||||
#[cfg(unix)]
|
||||
Err(_) => {
|
||||
// On Unix, depending on the implementation, we may get spurious
|
||||
// errors so make a note not to use bytes_available again and try
|
||||
// the non-blocking read anyway.
|
||||
self.bytes_available_failed = true;
|
||||
MIN_BUFFER_CAPACITY
|
||||
}
|
||||
Ok(bytes_available) => MIN_BUFFER_CAPACITY.max(bytes_available),
|
||||
}
|
||||
} else {
|
||||
MIN_BUFFER_CAPACITY
|
||||
};
|
||||
buffer.reserve(to_reserve);
|
||||
|
||||
// Safety: stderr.read only writes to the spare part of the buffer, it never reads from it
|
||||
match stderr
|
||||
.read(unsafe { &mut *(buffer.spare_capacity_mut() as *mut _ as *mut [u8]) })
|
||||
{
|
||||
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
// No data currently, yield back.
|
||||
break false;
|
||||
}
|
||||
Err(err) if err.kind() == std::io::ErrorKind::Interrupted => {
|
||||
// Interrupted, try again.
|
||||
continue;
|
||||
}
|
||||
Ok(bytes_read) if bytes_read != 0 => {
|
||||
// Safety: bytes_read bytes is written to spare part of the buffer
|
||||
unsafe { buffer.set_len(old_data_end + bytes_read) };
|
||||
let mut consumed = 0;
|
||||
for line in buffer.split_inclusive(|&b| b == b'\n') {
|
||||
// Only forward complete lines, leave the rest in the buffer.
|
||||
if let Some((b'\n', line)) = line.split_last() {
|
||||
consumed += line.len() + 1;
|
||||
write_warning(line);
|
||||
}
|
||||
}
|
||||
buffer.drain(..consumed);
|
||||
}
|
||||
res => {
|
||||
// End of stream: flush remaining data and bail.
|
||||
if old_data_end > 0 {
|
||||
write_warning(&buffer[..old_data_end]);
|
||||
}
|
||||
if let Err(err) = res {
|
||||
write_warning(
|
||||
format!("Failed to read from child stderr: {err}").as_bytes(),
|
||||
);
|
||||
}
|
||||
self.inner.take();
|
||||
break true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
pub(crate) fn set_non_blocking(&mut self) -> Result<(), Error> {
|
||||
assert!(!self.is_non_blocking);
|
||||
|
||||
#[cfg(unix)]
|
||||
if let Some((stderr, _)) = self.inner.as_ref() {
|
||||
crate::parallel::stderr::set_non_blocking(stderr)?;
|
||||
}
|
||||
|
||||
self.is_non_blocking = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
fn forward_all(&mut self) {
|
||||
while !self.forward_available() {}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
fn forward_all(&mut self) {
|
||||
let forward_result = self.forward_available();
|
||||
assert!(forward_result, "Should have consumed all data");
|
||||
}
|
||||
}
|
||||
|
||||
fn write_warning(line: &[u8]) {
|
||||
let stdout = io::stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
stdout.write_all(b"cargo:warning=").unwrap();
|
||||
stdout.write_all(line).unwrap();
|
||||
stdout.write_all(b"\n").unwrap();
|
||||
}
|
||||
|
||||
fn wait_on_child(
|
||||
cmd: &Command,
|
||||
program: &Path,
|
||||
child: &mut Child,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Result<(), Error> {
|
||||
StderrForwarder::new(child).forward_all();
|
||||
|
||||
let status = match child.wait() {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Failed to wait on spawned child process, command {:?} with args {}: {}.",
|
||||
cmd,
|
||||
program.display(),
|
||||
e
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
cargo_output.print_debug(&status);
|
||||
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Command {:?} with args {} did not execute successfully (status code {}).",
|
||||
cmd,
|
||||
program.display(),
|
||||
status
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the destination object path for each file in the input source files,
|
||||
/// and store them in the output Object.
|
||||
pub(crate) fn objects_from_files(files: &[Arc<Path>], dst: &Path) -> Result<Vec<Object>, Error> {
|
||||
let mut objects = Vec::with_capacity(files.len());
|
||||
for file in files {
|
||||
let basename = file
|
||||
.file_name()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidArgument,
|
||||
"No file_name for object file path!",
|
||||
)
|
||||
})?
|
||||
.to_string_lossy();
|
||||
let dirname = file
|
||||
.parent()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidArgument,
|
||||
"No parent for object file path!",
|
||||
)
|
||||
})?
|
||||
.to_string_lossy();
|
||||
|
||||
// Hash the dirname. This should prevent conflicts if we have multiple
|
||||
// object files with the same filename in different subfolders.
|
||||
let mut hasher = hash_map::DefaultHasher::new();
|
||||
hasher.write(dirname.to_string().as_bytes());
|
||||
let obj = dst
|
||||
.join(format!("{:016x}-{}", hasher.finish(), basename))
|
||||
.with_extension("o");
|
||||
|
||||
match obj.parent() {
|
||||
Some(s) => fs::create_dir_all(s)?,
|
||||
None => {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidArgument,
|
||||
"dst is an invalid path with no parent",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
objects.push(Object::new(file.to_path_buf(), obj));
|
||||
}
|
||||
|
||||
Ok(objects)
|
||||
}
|
||||
|
||||
pub(crate) fn run(
|
||||
cmd: &mut Command,
|
||||
program: impl AsRef<Path>,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Result<(), Error> {
|
||||
let program = program.as_ref();
|
||||
|
||||
let mut child = spawn(cmd, program, cargo_output)?;
|
||||
wait_on_child(cmd, program, &mut child, cargo_output)
|
||||
}
|
||||
|
||||
pub(crate) fn run_output(
|
||||
cmd: &mut Command,
|
||||
program: impl AsRef<Path>,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let program = program.as_ref();
|
||||
|
||||
cmd.stdout(Stdio::piped());
|
||||
|
||||
let mut child = spawn(cmd, program, cargo_output)?;
|
||||
|
||||
let mut stdout = vec![];
|
||||
child
|
||||
.stdout
|
||||
.take()
|
||||
.unwrap()
|
||||
.read_to_end(&mut stdout)
|
||||
.unwrap();
|
||||
|
||||
wait_on_child(cmd, program, &mut child, cargo_output)?;
|
||||
|
||||
Ok(stdout)
|
||||
}
|
||||
|
||||
pub(crate) fn spawn(
|
||||
cmd: &mut Command,
|
||||
program: &Path,
|
||||
cargo_output: &CargoOutput,
|
||||
) -> Result<Child, Error> {
|
||||
struct ResetStderr<'cmd>(&'cmd mut Command);
|
||||
|
||||
impl Drop for ResetStderr<'_> {
|
||||
fn drop(&mut self) {
|
||||
// Reset stderr to default to release pipe_writer so that print thread will
|
||||
// not block forever.
|
||||
self.0.stderr(Stdio::inherit());
|
||||
}
|
||||
}
|
||||
|
||||
cargo_output.print_debug(&format_args!("running: {:?}", cmd));
|
||||
|
||||
let cmd = ResetStderr(cmd);
|
||||
let child = cmd.0.stderr(cargo_output.stdio_for_warnings()).spawn();
|
||||
match child {
|
||||
Ok(child) => Ok(child),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
|
||||
let extra = if cfg!(windows) {
|
||||
" (see https://docs.rs/cc/latest/cc/#compile-time-requirements \
|
||||
for help)"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
Err(Error::new(
|
||||
ErrorKind::ToolNotFound,
|
||||
format!(
|
||||
"Failed to find tool. Is `{}` installed?{}",
|
||||
program.display(),
|
||||
extra
|
||||
),
|
||||
))
|
||||
}
|
||||
Err(e) => Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Command {:?} with args {} failed to start: {:?}",
|
||||
cmd.0,
|
||||
program.display(),
|
||||
e
|
||||
),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CmdAddOutputFileArgs {
|
||||
pub(crate) cuda: bool,
|
||||
pub(crate) is_assembler_msvc: bool,
|
||||
pub(crate) msvc: bool,
|
||||
pub(crate) clang: bool,
|
||||
pub(crate) gnu: bool,
|
||||
pub(crate) is_asm: bool,
|
||||
pub(crate) is_arm: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn command_add_output_file(cmd: &mut Command, dst: &Path, args: CmdAddOutputFileArgs) {
|
||||
if args.is_assembler_msvc
|
||||
|| !(!args.msvc || args.clang || args.gnu || args.cuda || (args.is_asm && args.is_arm))
|
||||
{
|
||||
let mut s = OsString::from("-Fo");
|
||||
s.push(dst);
|
||||
cmd.arg(s);
|
||||
} else {
|
||||
cmd.arg("-o").arg(dst);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
pub(crate) fn try_wait_on_child(
|
||||
cmd: &Command,
|
||||
program: &Path,
|
||||
child: &mut Child,
|
||||
stdout: &mut dyn io::Write,
|
||||
stderr_forwarder: &mut StderrForwarder,
|
||||
) -> Result<Option<()>, Error> {
|
||||
stderr_forwarder.forward_available();
|
||||
|
||||
match child.try_wait() {
|
||||
Ok(Some(status)) => {
|
||||
stderr_forwarder.forward_all();
|
||||
|
||||
let _ = writeln!(stdout, "{}", status);
|
||||
|
||||
if status.success() {
|
||||
Ok(Some(()))
|
||||
} else {
|
||||
Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Command {:?} with args {} did not execute successfully (status code {}).",
|
||||
cmd,
|
||||
program.display(),
|
||||
status
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => {
|
||||
stderr_forwarder.forward_all();
|
||||
Err(Error::new(
|
||||
ErrorKind::ToolExecError,
|
||||
format!(
|
||||
"Failed to wait on spawned child process, command {:?} with args {}: {}.",
|
||||
cmd,
|
||||
program.display(),
|
||||
e
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
7
vendor/cc/src/detect_compiler_family.c
vendored
Normal file
7
vendor/cc/src/detect_compiler_family.c
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
#ifdef __clang__
|
||||
#pragma message "clang"
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma message "gcc"
|
||||
#endif
|
4244
vendor/cc/src/lib.rs
vendored
Normal file
4244
vendor/cc/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
118
vendor/cc/src/parallel/async_executor.rs
vendored
Normal file
118
vendor/cc/src/parallel/async_executor.rs
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
use std::{
|
||||
cell::Cell,
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
ptr,
|
||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
|
||||
// Cloning just returns a new no-op raw waker
|
||||
|_| NOOP_RAW_WAKER,
|
||||
// `wake` does nothing
|
||||
|_| {},
|
||||
// `wake_by_ref` does nothing
|
||||
|_| {},
|
||||
// Dropping does nothing as we don't allocate anything
|
||||
|_| {},
|
||||
);
|
||||
const NOOP_RAW_WAKER: RawWaker = RawWaker::new(ptr::null(), &NOOP_WAKER_VTABLE);
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct YieldOnce(bool);
|
||||
|
||||
impl Future for YieldOnce {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
|
||||
let flag = &mut std::pin::Pin::into_inner(self).0;
|
||||
if !*flag {
|
||||
*flag = true;
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute the futures and return when they are all done.
|
||||
///
|
||||
/// Here we use our own homebrew async executor since cc is used in the build
|
||||
/// script of many popular projects, pulling in additional dependencies would
|
||||
/// significantly slow down its compilation.
|
||||
pub(crate) fn block_on<Fut1, Fut2>(
|
||||
mut fut1: Fut1,
|
||||
mut fut2: Fut2,
|
||||
has_made_progress: &Cell<bool>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
Fut1: Future<Output = Result<(), Error>>,
|
||||
Fut2: Future<Output = Result<(), Error>>,
|
||||
{
|
||||
// Shadows the future so that it can never be moved and is guaranteed
|
||||
// to be pinned.
|
||||
//
|
||||
// The same trick used in `pin!` macro.
|
||||
//
|
||||
// TODO: Once MSRV is bumped to 1.68, replace this with `std::pin::pin!`
|
||||
let mut fut1 = Some(unsafe { Pin::new_unchecked(&mut fut1) });
|
||||
let mut fut2 = Some(unsafe { Pin::new_unchecked(&mut fut2) });
|
||||
|
||||
// TODO: Once `Waker::noop` stablised and our MSRV is bumped to the version
|
||||
// which it is stablised, replace this with `Waker::noop`.
|
||||
let waker = unsafe { Waker::from_raw(NOOP_RAW_WAKER) };
|
||||
let mut context = Context::from_waker(&waker);
|
||||
|
||||
let mut backoff_cnt = 0;
|
||||
|
||||
loop {
|
||||
has_made_progress.set(false);
|
||||
|
||||
if let Some(fut) = fut2.as_mut() {
|
||||
if let Poll::Ready(res) = fut.as_mut().poll(&mut context) {
|
||||
fut2 = None;
|
||||
res?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fut) = fut1.as_mut() {
|
||||
if let Poll::Ready(res) = fut.as_mut().poll(&mut context) {
|
||||
fut1 = None;
|
||||
res?;
|
||||
}
|
||||
}
|
||||
|
||||
if fut1.is_none() && fut2.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if !has_made_progress.get() {
|
||||
if backoff_cnt > 3 {
|
||||
// We have yielded at least three times without making'
|
||||
// any progress, so we will sleep for a while.
|
||||
let duration = Duration::from_millis(100 * (backoff_cnt - 3).min(10));
|
||||
thread::sleep(duration);
|
||||
} else {
|
||||
// Given that we spawned a lot of compilation tasks, it is unlikely
|
||||
// that OS cannot find other ready task to execute.
|
||||
//
|
||||
// If all of them are done, then we will yield them and spawn more,
|
||||
// or simply return.
|
||||
//
|
||||
// Thus this will not be turned into a busy-wait loop and it will not
|
||||
// waste CPU resource.
|
||||
thread::yield_now();
|
||||
}
|
||||
}
|
||||
|
||||
backoff_cnt = if has_made_progress.get() {
|
||||
0
|
||||
} else {
|
||||
backoff_cnt + 1
|
||||
};
|
||||
}
|
||||
}
|
270
vendor/cc/src/parallel/job_token.rs
vendored
Normal file
270
vendor/cc/src/parallel/job_token.rs
vendored
Normal file
@ -0,0 +1,270 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
pub(crate) struct JobToken(PhantomData<()>);
|
||||
|
||||
impl JobToken {
|
||||
fn new() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for JobToken {
|
||||
fn drop(&mut self) {
|
||||
match JobTokenServer::new() {
|
||||
JobTokenServer::Inherited(jobserver) => jobserver.release_token_raw(),
|
||||
JobTokenServer::InProcess(jobserver) => jobserver.release_token_raw(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum JobTokenServer {
|
||||
Inherited(inherited_jobserver::JobServer),
|
||||
InProcess(inprocess_jobserver::JobServer),
|
||||
}
|
||||
|
||||
impl JobTokenServer {
|
||||
/// This function returns a static reference to the jobserver because
|
||||
/// - creating a jobserver from env is a bit fd-unsafe (e.g. the fd might
|
||||
/// be closed by other jobserver users in the process) and better do it
|
||||
/// at the start of the program.
|
||||
/// - in case a jobserver cannot be created from env (e.g. it's not
|
||||
/// present), we will create a global in-process only jobserver
|
||||
/// that has to be static so that it will be shared by all cc
|
||||
/// compilation.
|
||||
fn new() -> &'static Self {
|
||||
// TODO: Replace with a OnceLock once MSRV is 1.70
|
||||
static JOBSERVER: OnceCell<JobTokenServer> = OnceCell::new();
|
||||
|
||||
JOBSERVER.get_or_init(|| {
|
||||
unsafe { inherited_jobserver::JobServer::from_env() }
|
||||
.map(Self::Inherited)
|
||||
.unwrap_or_else(|| Self::InProcess(inprocess_jobserver::JobServer::new()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum ActiveJobTokenServer {
|
||||
Inherited(inherited_jobserver::ActiveJobServer<'static>),
|
||||
InProcess(&'static inprocess_jobserver::JobServer),
|
||||
}
|
||||
|
||||
impl ActiveJobTokenServer {
|
||||
pub(crate) fn new() -> Self {
|
||||
match JobTokenServer::new() {
|
||||
JobTokenServer::Inherited(inherited_jobserver) => {
|
||||
Self::Inherited(inherited_jobserver.enter_active())
|
||||
}
|
||||
JobTokenServer::InProcess(inprocess_jobserver) => Self::InProcess(inprocess_jobserver),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn acquire(&self) -> Result<JobToken, Error> {
|
||||
match &self {
|
||||
Self::Inherited(jobserver) => jobserver.acquire().await,
|
||||
Self::InProcess(jobserver) => Ok(jobserver.acquire().await),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod inherited_jobserver {
|
||||
use super::{JobToken, OnceCell};
|
||||
|
||||
use crate::{parallel::async_executor::YieldOnce, Error, ErrorKind};
|
||||
|
||||
use std::{
|
||||
io, mem,
|
||||
sync::{mpsc, Mutex, MutexGuard, PoisonError},
|
||||
};
|
||||
|
||||
pub(super) struct JobServer {
|
||||
/// Implicit token for this process which is obtained and will be
|
||||
/// released in parent. Since JobTokens only give back what they got,
|
||||
/// there should be at most one global implicit token in the wild.
|
||||
///
|
||||
/// Since Rust does not execute any `Drop` for global variables,
|
||||
/// we can't just put it back to jobserver and then re-acquire it at
|
||||
/// the end of the process.
|
||||
///
|
||||
/// Use `Mutex` to avoid race between acquire and release.
|
||||
/// If an `AtomicBool` is used, then it's possible for:
|
||||
/// - `release_token_raw`: Tries to set `global_implicit_token` to true, but it is already
|
||||
/// set to `true`, continue to release it to jobserver
|
||||
/// - `acquire` takes the global implicit token, set `global_implicit_token` to false
|
||||
/// - `release_token_raw` now writes the token back into the jobserver, while
|
||||
/// `global_implicit_token` is `false`
|
||||
///
|
||||
/// If the program exits here, then cc effectively increases parallelism by one, which is
|
||||
/// incorrect, hence we use a `Mutex` here.
|
||||
global_implicit_token: Mutex<bool>,
|
||||
inner: jobserver::Client,
|
||||
}
|
||||
|
||||
impl JobServer {
|
||||
pub(super) unsafe fn from_env() -> Option<Self> {
|
||||
jobserver::Client::from_env().map(|inner| Self {
|
||||
inner,
|
||||
global_implicit_token: Mutex::new(true),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_global_implicit_token(&self) -> MutexGuard<'_, bool> {
|
||||
self.global_implicit_token
|
||||
.lock()
|
||||
.unwrap_or_else(PoisonError::into_inner)
|
||||
}
|
||||
|
||||
/// All tokens except for the global implicit token will be put back into the jobserver
|
||||
/// immediately and they cannot be cached, since Rust does not call `Drop::drop` on
|
||||
/// global variables.
|
||||
pub(super) fn release_token_raw(&self) {
|
||||
let mut global_implicit_token = self.get_global_implicit_token();
|
||||
|
||||
if *global_implicit_token {
|
||||
// There's already a global implicit token, so this token must
|
||||
// be released back into jobserver.
|
||||
//
|
||||
// `release_raw` should not block
|
||||
let _ = self.inner.release_raw();
|
||||
} else {
|
||||
*global_implicit_token = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn enter_active(&self) -> ActiveJobServer<'_> {
|
||||
ActiveJobServer {
|
||||
jobserver: self,
|
||||
helper_thread: OnceCell::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct HelperThread {
|
||||
inner: jobserver::HelperThread,
|
||||
/// When rx is dropped, all the token stored within it will be dropped.
|
||||
rx: mpsc::Receiver<io::Result<jobserver::Acquired>>,
|
||||
}
|
||||
|
||||
impl HelperThread {
|
||||
fn new(jobserver: &JobServer) -> Result<Self, Error> {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
Ok(Self {
|
||||
rx,
|
||||
inner: jobserver.inner.clone().into_helper_thread(move |res| {
|
||||
let _ = tx.send(res);
|
||||
})?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ActiveJobServer<'a> {
|
||||
jobserver: &'a JobServer,
|
||||
helper_thread: OnceCell<HelperThread>,
|
||||
}
|
||||
|
||||
impl<'a> ActiveJobServer<'a> {
|
||||
pub(super) async fn acquire(&self) -> Result<JobToken, Error> {
|
||||
let mut has_requested_token = false;
|
||||
|
||||
loop {
|
||||
// Fast path
|
||||
if mem::replace(&mut *self.jobserver.get_global_implicit_token(), false) {
|
||||
break Ok(JobToken::new());
|
||||
}
|
||||
|
||||
match self.jobserver.inner.try_acquire() {
|
||||
Ok(Some(acquired)) => {
|
||||
acquired.drop_without_releasing();
|
||||
break Ok(JobToken::new());
|
||||
}
|
||||
Ok(None) => YieldOnce::default().await,
|
||||
Err(err) if err.kind() == io::ErrorKind::Unsupported => {
|
||||
// Fallback to creating a help thread with blocking acquire
|
||||
let helper_thread = self
|
||||
.helper_thread
|
||||
.get_or_try_init(|| HelperThread::new(self.jobserver))?;
|
||||
|
||||
match helper_thread.rx.try_recv() {
|
||||
Ok(res) => {
|
||||
let acquired = res?;
|
||||
acquired.drop_without_releasing();
|
||||
break Ok(JobToken::new());
|
||||
}
|
||||
Err(mpsc::TryRecvError::Disconnected) => break Err(Error::new(
|
||||
ErrorKind::JobserverHelpThreadError,
|
||||
"jobserver help thread has returned before ActiveJobServer is dropped",
|
||||
)),
|
||||
Err(mpsc::TryRecvError::Empty) => {
|
||||
if !has_requested_token {
|
||||
helper_thread.inner.request_token();
|
||||
has_requested_token = true;
|
||||
}
|
||||
YieldOnce::default().await
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => break Err(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod inprocess_jobserver {
|
||||
use super::JobToken;
|
||||
|
||||
use crate::parallel::async_executor::YieldOnce;
|
||||
|
||||
use std::{
|
||||
env::var,
|
||||
sync::atomic::{
|
||||
AtomicU32,
|
||||
Ordering::{AcqRel, Acquire},
|
||||
},
|
||||
};
|
||||
|
||||
pub(crate) struct JobServer(AtomicU32);
|
||||
|
||||
impl JobServer {
|
||||
pub(super) fn new() -> Self {
|
||||
// Use `NUM_JOBS` if set (it's configured by Cargo) and otherwise
|
||||
// just fall back to a semi-reasonable number.
|
||||
//
|
||||
// Note that we could use `num_cpus` here but it's an extra
|
||||
// dependency that will almost never be used, so
|
||||
// it's generally not too worth it.
|
||||
let mut parallelism = 4;
|
||||
// TODO: Use std::thread::available_parallelism as an upper bound
|
||||
// when MSRV is bumped.
|
||||
if let Ok(amt) = var("NUM_JOBS") {
|
||||
if let Ok(amt) = amt.parse() {
|
||||
parallelism = amt;
|
||||
}
|
||||
}
|
||||
|
||||
Self(AtomicU32::new(parallelism))
|
||||
}
|
||||
|
||||
pub(super) async fn acquire(&self) -> JobToken {
|
||||
loop {
|
||||
let res = self
|
||||
.0
|
||||
.fetch_update(AcqRel, Acquire, |tokens| tokens.checked_sub(1));
|
||||
|
||||
if res.is_ok() {
|
||||
break JobToken::new();
|
||||
}
|
||||
|
||||
YieldOnce::default().await
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn release_token_raw(&self) {
|
||||
self.0.fetch_add(1, AcqRel);
|
||||
}
|
||||
}
|
||||
}
|
3
vendor/cc/src/parallel/mod.rs
vendored
Normal file
3
vendor/cc/src/parallel/mod.rs
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
pub(crate) mod async_executor;
|
||||
pub(crate) mod job_token;
|
||||
pub(crate) mod stderr;
|
90
vendor/cc/src/parallel/stderr.rs
vendored
Normal file
90
vendor/cc/src/parallel/stderr.rs
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
/// Helpers functions for [ChildStderr].
|
||||
use std::{convert::TryInto, process::ChildStderr};
|
||||
|
||||
use crate::{Error, ErrorKind};
|
||||
|
||||
#[cfg(all(not(unix), not(windows)))]
|
||||
compile_error!("Only unix and windows support non-blocking pipes! For other OSes, disable the parallel feature.");
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_flags(fd: std::os::unix::io::RawFd) -> Result<i32, Error> {
|
||||
let flags = unsafe { libc::fcntl(fd, libc::F_GETFL, 0) };
|
||||
if flags == -1 {
|
||||
Err(Error::new(
|
||||
ErrorKind::IOError,
|
||||
format!(
|
||||
"Failed to get flags for pipe {}: {}",
|
||||
fd,
|
||||
std::io::Error::last_os_error()
|
||||
),
|
||||
))
|
||||
} else {
|
||||
Ok(flags)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn set_flags(fd: std::os::unix::io::RawFd, flags: std::os::raw::c_int) -> Result<(), Error> {
|
||||
if unsafe { libc::fcntl(fd, libc::F_SETFL, flags) } == -1 {
|
||||
Err(Error::new(
|
||||
ErrorKind::IOError,
|
||||
format!(
|
||||
"Failed to set flags for pipe {}: {}",
|
||||
fd,
|
||||
std::io::Error::last_os_error()
|
||||
),
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn set_non_blocking(pipe: &impl std::os::unix::io::AsRawFd) -> Result<(), Error> {
|
||||
// On Unix, switch the pipe to non-blocking mode.
|
||||
// On Windows, we have a different way to be non-blocking.
|
||||
let fd = pipe.as_raw_fd();
|
||||
|
||||
let flags = get_flags(fd)?;
|
||||
set_flags(fd, flags | libc::O_NONBLOCK)
|
||||
}
|
||||
|
||||
pub fn bytes_available(stderr: &mut ChildStderr) -> Result<usize, Error> {
|
||||
let mut bytes_available = 0;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use crate::windows::windows_sys::PeekNamedPipe;
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
use std::ptr::null_mut;
|
||||
if unsafe {
|
||||
PeekNamedPipe(
|
||||
stderr.as_raw_handle(),
|
||||
null_mut(),
|
||||
0,
|
||||
null_mut(),
|
||||
&mut bytes_available,
|
||||
null_mut(),
|
||||
)
|
||||
} == 0
|
||||
{
|
||||
return Err(Error::new(
|
||||
ErrorKind::IOError,
|
||||
format!(
|
||||
"PeekNamedPipe failed with {}",
|
||||
std::io::Error::last_os_error()
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::io::AsRawFd;
|
||||
if unsafe { libc::ioctl(stderr.as_raw_fd(), libc::FIONREAD, &mut bytes_available) } != 0 {
|
||||
return Err(Error::new(
|
||||
ErrorKind::IOError,
|
||||
format!("ioctl failed with {}", std::io::Error::last_os_error()),
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(bytes_available.try_into().unwrap())
|
||||
}
|
14
vendor/cc/src/target_info.rs
vendored
Normal file
14
vendor/cc/src/target_info.rs
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
//! This file is generated code. Please edit the generator
|
||||
//! in dev-tools/gen-target-info if you need to make changes.
|
||||
|
||||
pub const RISCV_ARCH_MAPPING: &[(&str, &str)] = &[
|
||||
("riscv32gc", "riscv32"),
|
||||
("riscv32i", "riscv32"),
|
||||
("riscv32im", "riscv32"),
|
||||
("riscv32ima", "riscv32"),
|
||||
("riscv32imac", "riscv32"),
|
||||
("riscv32imafc", "riscv32"),
|
||||
("riscv32imc", "riscv32"),
|
||||
("riscv64gc", "riscv64"),
|
||||
("riscv64imac", "riscv64"),
|
||||
];
|
84
vendor/cc/src/tempfile.rs
vendored
Normal file
84
vendor/cc/src/tempfile.rs
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
use std::{
|
||||
collections::hash_map::RandomState,
|
||||
fs::{remove_file, File, OpenOptions},
|
||||
hash::{BuildHasher, Hasher},
|
||||
io, os,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[cfg(not(any(unix, target_os = "wasi", windows)))]
|
||||
compile_error!("Your system is not supported since cc cannot create named tempfile");
|
||||
|
||||
fn rand() -> u64 {
|
||||
RandomState::new().build_hasher().finish()
|
||||
}
|
||||
|
||||
fn tmpname(suffix: &str) -> String {
|
||||
format!("{}{}", rand(), suffix)
|
||||
}
|
||||
|
||||
fn create_named(path: &Path) -> io::Result<File> {
|
||||
let mut open_options = OpenOptions::new();
|
||||
|
||||
open_options.read(true).write(true).create_new(true);
|
||||
|
||||
#[cfg(all(unix, not(target_os = "wasi")))]
|
||||
<OpenOptions as os::unix::fs::OpenOptionsExt>::mode(&mut open_options, 0o600);
|
||||
|
||||
#[cfg(windows)]
|
||||
<OpenOptions as os::windows::fs::OpenOptionsExt>::custom_flags(
|
||||
&mut open_options,
|
||||
crate::windows::windows_sys::FILE_ATTRIBUTE_TEMPORARY,
|
||||
);
|
||||
|
||||
open_options.open(path)
|
||||
}
|
||||
|
||||
pub(super) struct NamedTempfile {
|
||||
path: PathBuf,
|
||||
file: Option<File>,
|
||||
}
|
||||
|
||||
impl NamedTempfile {
|
||||
pub(super) fn new(base: &Path, suffix: &str) -> io::Result<Self> {
|
||||
for _ in 0..10 {
|
||||
let path = base.join(tmpname(suffix));
|
||||
match create_named(&path) {
|
||||
Ok(file) => {
|
||||
return Ok(Self {
|
||||
file: Some(file),
|
||||
path,
|
||||
})
|
||||
}
|
||||
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => continue,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
}
|
||||
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::AlreadyExists,
|
||||
format!(
|
||||
"too many temporary files exist in base `{}` with suffix `{}`",
|
||||
base.display(),
|
||||
suffix
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
pub(super) fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub(super) fn take_file(&mut self) -> Option<File> {
|
||||
self.file.take()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for NamedTempfile {
|
||||
fn drop(&mut self) {
|
||||
// On Windows you have to close all handle to it before
|
||||
// removing the file.
|
||||
self.file.take();
|
||||
let _ = remove_file(&self.path);
|
||||
}
|
||||
}
|
474
vendor/cc/src/tool.rs
vendored
Normal file
474
vendor/cc/src/tool.rs
vendored
Normal file
@ -0,0 +1,474 @@
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
env,
|
||||
ffi::{OsStr, OsString},
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
sync::RwLock,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
command_helpers::{run_output, CargoOutput},
|
||||
run,
|
||||
tempfile::NamedTempfile,
|
||||
Error, ErrorKind,
|
||||
};
|
||||
|
||||
/// Configuration used to represent an invocation of a C compiler.
|
||||
///
|
||||
/// This can be used to figure out what compiler is in use, what the arguments
|
||||
/// to it are, and what the environment variables look like for the compiler.
|
||||
/// This can be used to further configure other build systems (e.g. forward
|
||||
/// along CC and/or CFLAGS) or the `to_command` method can be used to run the
|
||||
/// compiler itself.
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Tool {
|
||||
pub(crate) path: PathBuf,
|
||||
pub(crate) cc_wrapper_path: Option<PathBuf>,
|
||||
pub(crate) cc_wrapper_args: Vec<OsString>,
|
||||
pub(crate) args: Vec<OsString>,
|
||||
pub(crate) env: Vec<(OsString, OsString)>,
|
||||
pub(crate) family: ToolFamily,
|
||||
pub(crate) cuda: bool,
|
||||
pub(crate) removed_args: Vec<OsString>,
|
||||
pub(crate) has_internal_target_arg: bool,
|
||||
}
|
||||
|
||||
impl Tool {
|
||||
pub(crate) fn new(
|
||||
path: PathBuf,
|
||||
cached_compiler_family: &RwLock<HashMap<Box<Path>, ToolFamily>>,
|
||||
cargo_output: &CargoOutput,
|
||||
out_dir: Option<&Path>,
|
||||
) -> Self {
|
||||
Self::with_features(
|
||||
path,
|
||||
None,
|
||||
false,
|
||||
cached_compiler_family,
|
||||
cargo_output,
|
||||
out_dir,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn with_clang_driver(
|
||||
path: PathBuf,
|
||||
clang_driver: Option<&str>,
|
||||
cached_compiler_family: &RwLock<HashMap<Box<Path>, ToolFamily>>,
|
||||
cargo_output: &CargoOutput,
|
||||
out_dir: Option<&Path>,
|
||||
) -> Self {
|
||||
Self::with_features(
|
||||
path,
|
||||
clang_driver,
|
||||
false,
|
||||
cached_compiler_family,
|
||||
cargo_output,
|
||||
out_dir,
|
||||
)
|
||||
}
|
||||
|
||||
/// Explicitly set the `ToolFamily`, skipping name-based detection.
|
||||
pub(crate) fn with_family(path: PathBuf, family: ToolFamily) -> Self {
|
||||
Self {
|
||||
path,
|
||||
cc_wrapper_path: None,
|
||||
cc_wrapper_args: Vec::new(),
|
||||
args: Vec::new(),
|
||||
env: Vec::new(),
|
||||
family,
|
||||
cuda: false,
|
||||
removed_args: Vec::new(),
|
||||
has_internal_target_arg: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_features(
|
||||
path: PathBuf,
|
||||
clang_driver: Option<&str>,
|
||||
cuda: bool,
|
||||
cached_compiler_family: &RwLock<HashMap<Box<Path>, ToolFamily>>,
|
||||
cargo_output: &CargoOutput,
|
||||
out_dir: Option<&Path>,
|
||||
) -> Self {
|
||||
fn is_zig_cc(path: &Path, cargo_output: &CargoOutput) -> bool {
|
||||
run_output(
|
||||
Command::new(path).arg("--version"),
|
||||
path,
|
||||
// tool detection issues should always be shown as warnings
|
||||
cargo_output,
|
||||
)
|
||||
.map(|o| String::from_utf8_lossy(&o).contains("ziglang"))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn detect_family_inner(
|
||||
path: &Path,
|
||||
cargo_output: &CargoOutput,
|
||||
out_dir: Option<&Path>,
|
||||
) -> Result<ToolFamily, Error> {
|
||||
let out_dir = out_dir
|
||||
.map(Cow::Borrowed)
|
||||
.unwrap_or_else(|| Cow::Owned(env::temp_dir()));
|
||||
|
||||
// Ensure all the parent directories exist otherwise temp file creation
|
||||
// will fail
|
||||
std::fs::create_dir_all(&out_dir).map_err(|err| Error {
|
||||
kind: ErrorKind::IOError,
|
||||
message: format!("failed to create OUT_DIR '{}': {}", out_dir.display(), err)
|
||||
.into(),
|
||||
})?;
|
||||
|
||||
let mut tmp =
|
||||
NamedTempfile::new(&out_dir, "detect_compiler_family.c").map_err(|err| Error {
|
||||
kind: ErrorKind::IOError,
|
||||
message: format!(
|
||||
"failed to create detect_compiler_family.c temp file in '{}': {}",
|
||||
out_dir.display(),
|
||||
err
|
||||
)
|
||||
.into(),
|
||||
})?;
|
||||
let mut tmp_file = tmp.take_file().unwrap();
|
||||
tmp_file.write_all(include_bytes!("detect_compiler_family.c"))?;
|
||||
// Close the file handle *now*, otherwise the compiler may fail to open it on Windows
|
||||
// (#1082). The file stays on disk and its path remains valid until `tmp` is dropped.
|
||||
tmp_file.flush()?;
|
||||
tmp_file.sync_data()?;
|
||||
drop(tmp_file);
|
||||
|
||||
let stdout = run_output(
|
||||
Command::new(path).arg("-E").arg(tmp.path()),
|
||||
path,
|
||||
// When expanding the file, the compiler prints a lot of information to stderr
|
||||
// that it is not an error, but related to expanding itself.
|
||||
//
|
||||
// cc would have to disable warning here to prevent generation of too many warnings.
|
||||
&{
|
||||
let mut cargo_output = cargo_output.clone();
|
||||
cargo_output.warnings = cargo_output.debug;
|
||||
cargo_output
|
||||
},
|
||||
)?;
|
||||
let stdout = String::from_utf8_lossy(&stdout);
|
||||
|
||||
cargo_output.print_debug(&stdout);
|
||||
|
||||
// https://gitlab.kitware.com/cmake/cmake/-/blob/69a2eeb9dff5b60f2f1e5b425002a0fd45b7cadb/Modules/CMakeDetermineCompilerId.cmake#L267-271
|
||||
let accepts_cl_style_flags =
|
||||
run(Command::new(path).arg("-?").stdout(Stdio::null()), path, &{
|
||||
// the errors are not errors!
|
||||
let mut cargo_output = cargo_output.clone();
|
||||
cargo_output.warnings = cargo_output.debug;
|
||||
cargo_output
|
||||
})
|
||||
.is_ok();
|
||||
|
||||
let clang = stdout.contains(r#""clang""#);
|
||||
let gcc = stdout.contains(r#""gcc""#);
|
||||
|
||||
match (clang, accepts_cl_style_flags, gcc) {
|
||||
(clang_cl, true, _) => Ok(ToolFamily::Msvc { clang_cl }),
|
||||
(true, false, _) => Ok(ToolFamily::Clang {
|
||||
zig_cc: is_zig_cc(path, cargo_output),
|
||||
}),
|
||||
(false, false, true) => Ok(ToolFamily::Gnu),
|
||||
(false, false, false) => {
|
||||
cargo_output.print_warning(&"Compiler family detection failed since it does not define `__clang__`, `__GNUC__` or `_MSC_VER`, fallback to treating it as GNU");
|
||||
Err(Error::new(
|
||||
ErrorKind::ToolFamilyMacroNotFound,
|
||||
"Expects macro `__clang__`, `__GNUC__` or `_MSC_VER`, but found none",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
let detect_family = |path: &Path| -> Result<ToolFamily, Error> {
|
||||
if let Some(family) = cached_compiler_family.read().unwrap().get(path) {
|
||||
return Ok(*family);
|
||||
}
|
||||
|
||||
let family = detect_family_inner(path, cargo_output, out_dir)?;
|
||||
cached_compiler_family
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(path.into(), family);
|
||||
Ok(family)
|
||||
};
|
||||
|
||||
let family = detect_family(&path).unwrap_or_else(|e| {
|
||||
cargo_output.print_warning(&format_args!(
|
||||
"Compiler family detection failed due to error: {}",
|
||||
e
|
||||
));
|
||||
match path.file_name().map(OsStr::to_string_lossy) {
|
||||
Some(fname) if fname.contains("clang-cl") => ToolFamily::Msvc { clang_cl: true },
|
||||
Some(fname) if fname.ends_with("cl") || fname == "cl.exe" => {
|
||||
ToolFamily::Msvc { clang_cl: false }
|
||||
}
|
||||
Some(fname) if fname.contains("clang") => match clang_driver {
|
||||
Some("cl") => ToolFamily::Msvc { clang_cl: true },
|
||||
_ => ToolFamily::Clang {
|
||||
zig_cc: is_zig_cc(&path, cargo_output),
|
||||
},
|
||||
},
|
||||
Some(fname) if fname.contains("zig") => ToolFamily::Clang { zig_cc: true },
|
||||
_ => ToolFamily::Gnu,
|
||||
}
|
||||
});
|
||||
|
||||
Tool {
|
||||
path,
|
||||
cc_wrapper_path: None,
|
||||
cc_wrapper_args: Vec::new(),
|
||||
args: Vec::new(),
|
||||
env: Vec::new(),
|
||||
family,
|
||||
cuda,
|
||||
removed_args: Vec::new(),
|
||||
has_internal_target_arg: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an argument to be stripped from the final command arguments.
|
||||
pub(crate) fn remove_arg(&mut self, flag: OsString) {
|
||||
self.removed_args.push(flag);
|
||||
}
|
||||
|
||||
/// Push an "exotic" flag to the end of the compiler's arguments list.
|
||||
///
|
||||
/// Nvidia compiler accepts only the most common compiler flags like `-D`,
|
||||
/// `-I`, `-c`, etc. Options meant specifically for the underlying
|
||||
/// host C++ compiler have to be prefixed with `-Xcompiler`.
|
||||
/// [Another possible future application for this function is passing
|
||||
/// clang-specific flags to clang-cl, which otherwise accepts only
|
||||
/// MSVC-specific options.]
|
||||
pub(crate) fn push_cc_arg(&mut self, flag: OsString) {
|
||||
if self.cuda {
|
||||
self.args.push("-Xcompiler".into());
|
||||
}
|
||||
self.args.push(flag);
|
||||
}
|
||||
|
||||
/// Checks if an argument or flag has already been specified or conflicts.
|
||||
///
|
||||
/// Currently only checks optimization flags.
|
||||
pub(crate) fn is_duplicate_opt_arg(&self, flag: &OsString) -> bool {
|
||||
let flag = flag.to_str().unwrap();
|
||||
let mut chars = flag.chars();
|
||||
|
||||
// Only duplicate check compiler flags
|
||||
if self.is_like_msvc() {
|
||||
if chars.next() != Some('/') {
|
||||
return false;
|
||||
}
|
||||
} else if (self.is_like_gnu() || self.is_like_clang()) && chars.next() != Some('-') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for existing optimization flags (-O, /O)
|
||||
if chars.next() == Some('O') {
|
||||
return self
|
||||
.args()
|
||||
.iter()
|
||||
.any(|a| a.to_str().unwrap_or("").chars().nth(1) == Some('O'));
|
||||
}
|
||||
|
||||
// TODO Check for existing -m..., -m...=..., /arch:... flags
|
||||
false
|
||||
}
|
||||
|
||||
/// Don't push optimization arg if it conflicts with existing args.
|
||||
pub(crate) fn push_opt_unless_duplicate(&mut self, flag: OsString) {
|
||||
if self.is_duplicate_opt_arg(&flag) {
|
||||
println!("Info: Ignoring duplicate arg {:?}", &flag);
|
||||
} else {
|
||||
self.push_cc_arg(flag);
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts this compiler into a `Command` that's ready to be run.
|
||||
///
|
||||
/// This is useful for when the compiler needs to be executed and the
|
||||
/// command returned will already have the initial arguments and environment
|
||||
/// variables configured.
|
||||
pub fn to_command(&self) -> Command {
|
||||
let mut cmd = match self.cc_wrapper_path {
|
||||
Some(ref cc_wrapper_path) => {
|
||||
let mut cmd = Command::new(cc_wrapper_path);
|
||||
cmd.arg(&self.path);
|
||||
cmd
|
||||
}
|
||||
None => Command::new(&self.path),
|
||||
};
|
||||
cmd.args(&self.cc_wrapper_args);
|
||||
|
||||
let value = self
|
||||
.args
|
||||
.iter()
|
||||
.filter(|a| !self.removed_args.contains(a))
|
||||
.collect::<Vec<_>>();
|
||||
cmd.args(&value);
|
||||
|
||||
for (k, v) in self.env.iter() {
|
||||
cmd.env(k, v);
|
||||
}
|
||||
cmd
|
||||
}
|
||||
|
||||
/// Returns the path for this compiler.
|
||||
///
|
||||
/// Note that this may not be a path to a file on the filesystem, e.g. "cc",
|
||||
/// but rather something which will be resolved when a process is spawned.
|
||||
pub fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// Returns the default set of arguments to the compiler needed to produce
|
||||
/// executables for the target this compiler generates.
|
||||
pub fn args(&self) -> &[OsString] {
|
||||
&self.args
|
||||
}
|
||||
|
||||
/// Returns the set of environment variables needed for this compiler to
|
||||
/// operate.
|
||||
///
|
||||
/// This is typically only used for MSVC compilers currently.
|
||||
pub fn env(&self) -> &[(OsString, OsString)] {
|
||||
&self.env
|
||||
}
|
||||
|
||||
/// Returns the compiler command in format of CC environment variable.
|
||||
/// Or empty string if CC env was not present
|
||||
///
|
||||
/// This is typically used by configure script
|
||||
pub fn cc_env(&self) -> OsString {
|
||||
match self.cc_wrapper_path {
|
||||
Some(ref cc_wrapper_path) => {
|
||||
let mut cc_env = cc_wrapper_path.as_os_str().to_owned();
|
||||
cc_env.push(" ");
|
||||
cc_env.push(self.path.to_path_buf().into_os_string());
|
||||
for arg in self.cc_wrapper_args.iter() {
|
||||
cc_env.push(" ");
|
||||
cc_env.push(arg);
|
||||
}
|
||||
cc_env
|
||||
}
|
||||
None => OsString::from(""),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the compiler flags in format of CFLAGS environment variable.
|
||||
/// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS
|
||||
/// This is typically used by configure script
|
||||
pub fn cflags_env(&self) -> OsString {
|
||||
let mut flags = OsString::new();
|
||||
for (i, arg) in self.args.iter().enumerate() {
|
||||
if i > 0 {
|
||||
flags.push(" ");
|
||||
}
|
||||
flags.push(arg);
|
||||
}
|
||||
flags
|
||||
}
|
||||
|
||||
/// Whether the tool is GNU Compiler Collection-like.
|
||||
pub fn is_like_gnu(&self) -> bool {
|
||||
self.family == ToolFamily::Gnu
|
||||
}
|
||||
|
||||
/// Whether the tool is Clang-like.
|
||||
pub fn is_like_clang(&self) -> bool {
|
||||
matches!(self.family, ToolFamily::Clang { .. })
|
||||
}
|
||||
|
||||
/// Whether the tool is AppleClang under .xctoolchain
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub(crate) fn is_xctoolchain_clang(&self) -> bool {
|
||||
let path = self.path.to_string_lossy();
|
||||
path.contains(".xctoolchain/")
|
||||
}
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
pub(crate) fn is_xctoolchain_clang(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Whether the tool is MSVC-like.
|
||||
pub fn is_like_msvc(&self) -> bool {
|
||||
matches!(self.family, ToolFamily::Msvc { .. })
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the family of tools this tool belongs to.
|
||||
///
|
||||
/// Each family of tools differs in how and what arguments they accept.
|
||||
///
|
||||
/// Detection of a family is done on best-effort basis and may not accurately reflect the tool.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ToolFamily {
|
||||
/// Tool is GNU Compiler Collection-like.
|
||||
Gnu,
|
||||
/// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags
|
||||
/// and its cross-compilation approach is different.
|
||||
Clang { zig_cc: bool },
|
||||
/// Tool is the MSVC cl.exe.
|
||||
Msvc { clang_cl: bool },
|
||||
}
|
||||
|
||||
impl ToolFamily {
|
||||
/// What the flag to request debug info for this family of tools look like
|
||||
pub(crate) fn add_debug_flags(&self, cmd: &mut Tool, dwarf_version: Option<u32>) {
|
||||
match *self {
|
||||
ToolFamily::Msvc { .. } => {
|
||||
cmd.push_cc_arg("-Z7".into());
|
||||
}
|
||||
ToolFamily::Gnu | ToolFamily::Clang { .. } => {
|
||||
cmd.push_cc_arg(
|
||||
dwarf_version
|
||||
.map_or_else(|| "-g".into(), |v| format!("-gdwarf-{}", v))
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// What the flag to force frame pointers.
|
||||
pub(crate) fn add_force_frame_pointer(&self, cmd: &mut Tool) {
|
||||
match *self {
|
||||
ToolFamily::Gnu | ToolFamily::Clang { .. } => {
|
||||
cmd.push_cc_arg("-fno-omit-frame-pointer".into());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
/// What the flags to enable all warnings
|
||||
pub(crate) fn warnings_flags(&self) -> &'static str {
|
||||
match *self {
|
||||
ToolFamily::Msvc { .. } => "-W4",
|
||||
ToolFamily::Gnu | ToolFamily::Clang { .. } => "-Wall",
|
||||
}
|
||||
}
|
||||
|
||||
/// What the flags to enable extra warnings
|
||||
pub(crate) fn extra_warnings_flags(&self) -> Option<&'static str> {
|
||||
match *self {
|
||||
ToolFamily::Msvc { .. } => None,
|
||||
ToolFamily::Gnu | ToolFamily::Clang { .. } => Some("-Wextra"),
|
||||
}
|
||||
}
|
||||
|
||||
/// What the flag to turn warning into errors
|
||||
pub(crate) fn warnings_to_errors_flag(&self) -> &'static str {
|
||||
match *self {
|
||||
ToolFamily::Msvc { .. } => "-WX",
|
||||
ToolFamily::Gnu | ToolFamily::Clang { .. } => "-Werror",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn verbose_stderr(&self) -> bool {
|
||||
matches!(*self, ToolFamily::Clang { .. })
|
||||
}
|
||||
}
|
45
vendor/cc/src/utilities.rs
vendored
Normal file
45
vendor/cc/src/utilities.rs
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
fmt::{self, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
pub(super) struct JoinOsStrs<'a, T> {
|
||||
pub(super) slice: &'a [T],
|
||||
pub(super) delimiter: char,
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for JoinOsStrs<'_, T>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let len = self.slice.len();
|
||||
for (index, os_str) in self.slice.iter().enumerate() {
|
||||
// TODO: Use OsStr::display once it is stablised,
|
||||
// Path and OsStr has the same `Display` impl
|
||||
write!(f, "{}", Path::new(os_str).display())?;
|
||||
if index + 1 < len {
|
||||
f.write_char(self.delimiter)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct OptionOsStrDisplay<T>(pub(super) Option<T>);
|
||||
|
||||
impl<T> fmt::Display for OptionOsStrDisplay<T>
|
||||
where
|
||||
T: AsRef<OsStr>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// TODO: Use OsStr::display once it is stablised
|
||||
// Path and OsStr has the same `Display` impl
|
||||
if let Some(os_str) = self.0.as_ref() {
|
||||
write!(f, "Some({})", Path::new(os_str).display())
|
||||
} else {
|
||||
f.write_str("None")
|
||||
}
|
||||
}
|
||||
}
|
110
vendor/cc/src/windows/com.rs
vendored
Normal file
110
vendor/cc/src/windows/com.rs
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
// Copyright © 2017 winapi-rs developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
|
||||
// All files in the project carrying such notice may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::windows::{
|
||||
winapi::{IUnknown, Interface},
|
||||
windows_sys::{
|
||||
CoInitializeEx, SysFreeString, SysStringLen, BSTR, COINIT_MULTITHREADED, HRESULT, S_FALSE,
|
||||
S_OK,
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
ffi::OsString,
|
||||
ops::Deref,
|
||||
os::windows::ffi::OsStringExt,
|
||||
ptr::{null, null_mut},
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
pub fn initialize() -> Result<(), HRESULT> {
|
||||
let err = unsafe { CoInitializeEx(null(), COINIT_MULTITHREADED.try_into().unwrap()) };
|
||||
if err != S_OK && err != S_FALSE {
|
||||
// S_FALSE just means COM is already initialized
|
||||
Err(err)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ComPtr<T>(*mut T)
|
||||
where
|
||||
T: Interface;
|
||||
impl<T> ComPtr<T>
|
||||
where
|
||||
T: Interface,
|
||||
{
|
||||
/// Creates a `ComPtr` to wrap a raw pointer.
|
||||
/// It takes ownership over the pointer which means it does __not__ call `AddRef`.
|
||||
/// `T` __must__ be a COM interface that inherits from `IUnknown`.
|
||||
pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
|
||||
assert!(!ptr.is_null());
|
||||
ComPtr(ptr)
|
||||
}
|
||||
/// For internal use only.
|
||||
fn as_unknown(&self) -> &IUnknown {
|
||||
unsafe { &*(self.0 as *mut IUnknown) }
|
||||
}
|
||||
/// Performs `QueryInterface` fun.
|
||||
pub fn cast<U>(&self) -> Result<ComPtr<U>, i32>
|
||||
where
|
||||
U: Interface,
|
||||
{
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) };
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(unsafe { ComPtr::from_raw(obj as *mut U) })
|
||||
}
|
||||
}
|
||||
impl<T> Deref for ComPtr<T>
|
||||
where
|
||||
T: Interface,
|
||||
{
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.0 }
|
||||
}
|
||||
}
|
||||
impl<T> Clone for ComPtr<T>
|
||||
where
|
||||
T: Interface,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
self.as_unknown().AddRef();
|
||||
ComPtr::from_raw(self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> Drop for ComPtr<T>
|
||||
where
|
||||
T: Interface,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.as_unknown().Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct BStr(BSTR);
|
||||
impl BStr {
|
||||
pub unsafe fn from_raw(s: BSTR) -> BStr {
|
||||
BStr(s)
|
||||
}
|
||||
pub fn to_osstring(&self) -> OsString {
|
||||
let len = unsafe { SysStringLen(self.0) };
|
||||
let slice = unsafe { from_raw_parts(self.0, len as usize) };
|
||||
OsStringExt::from_wide(slice)
|
||||
}
|
||||
}
|
||||
impl Drop for BStr {
|
||||
fn drop(&mut self) {
|
||||
unsafe { SysFreeString(self.0) };
|
||||
}
|
||||
}
|
1221
vendor/cc/src/windows/find_tools.rs
vendored
Normal file
1221
vendor/cc/src/windows/find_tools.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
20
vendor/cc/src/windows/mod.rs
vendored
Normal file
20
vendor/cc/src/windows/mod.rs
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
//! These modules are all glue to support reading the MSVC version from
|
||||
//! the registry and from COM interfaces.
|
||||
|
||||
// This is used in the crate's public API, so don't use #[cfg(windows)]
|
||||
pub mod find_tools;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) mod windows_sys;
|
||||
|
||||
#[cfg(windows)]
|
||||
mod registry;
|
||||
#[cfg(windows)]
|
||||
#[macro_use]
|
||||
mod winapi;
|
||||
#[cfg(windows)]
|
||||
mod com;
|
||||
#[cfg(windows)]
|
||||
mod setup_config;
|
||||
#[cfg(windows)]
|
||||
mod vs_instances;
|
191
vendor/cc/src/windows/registry.rs
vendored
Normal file
191
vendor/cc/src/windows/registry.rs
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::windows::windows_sys::{
|
||||
RegCloseKey, RegEnumKeyExW, RegOpenKeyExW, RegQueryValueExW, ERROR_NO_MORE_ITEMS,
|
||||
ERROR_SUCCESS, HKEY, HKEY_LOCAL_MACHINE, KEY_READ, KEY_WOW64_32KEY, REG_SZ,
|
||||
};
|
||||
use std::{
|
||||
ffi::{OsStr, OsString},
|
||||
io,
|
||||
ops::RangeFrom,
|
||||
os::windows::prelude::*,
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
/// Must never be `HKEY_PERFORMANCE_DATA`.
|
||||
pub(crate) struct RegistryKey(Repr);
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type DWORD = u32;
|
||||
|
||||
struct OwnedKey(HKEY);
|
||||
|
||||
/// Note: must not encode `HKEY_PERFORMANCE_DATA` or one of its subkeys.
|
||||
enum Repr {
|
||||
/// `HKEY_LOCAL_MACHINE`.
|
||||
LocalMachine,
|
||||
/// A subkey of `HKEY_LOCAL_MACHINE`.
|
||||
Owned(OwnedKey),
|
||||
}
|
||||
|
||||
pub struct Iter<'a> {
|
||||
idx: RangeFrom<DWORD>,
|
||||
key: &'a RegistryKey,
|
||||
}
|
||||
|
||||
unsafe impl Sync for Repr {}
|
||||
unsafe impl Send for Repr {}
|
||||
|
||||
pub(crate) const LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::LocalMachine);
|
||||
|
||||
impl RegistryKey {
|
||||
fn raw(&self) -> HKEY {
|
||||
match self.0 {
|
||||
Repr::LocalMachine => HKEY_LOCAL_MACHINE,
|
||||
Repr::Owned(ref val) => val.0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Open a sub-key of `self`.
|
||||
pub fn open(&self, key: &OsStr) -> io::Result<RegistryKey> {
|
||||
let key = key.encode_wide().chain(Some(0)).collect::<Vec<_>>();
|
||||
let mut ret = null_mut();
|
||||
let err = unsafe {
|
||||
RegOpenKeyExW(
|
||||
self.raw(),
|
||||
key.as_ptr(),
|
||||
0,
|
||||
KEY_READ | KEY_WOW64_32KEY,
|
||||
&mut ret,
|
||||
)
|
||||
};
|
||||
if err == ERROR_SUCCESS {
|
||||
Ok(RegistryKey(Repr::Owned(OwnedKey(ret))))
|
||||
} else {
|
||||
Err(io::Error::from_raw_os_error(err as i32))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter {
|
||||
Iter {
|
||||
idx: 0..,
|
||||
key: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn query_str(&self, name: &str) -> io::Result<OsString> {
|
||||
let name: &OsStr = name.as_ref();
|
||||
let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>();
|
||||
let mut len = 0;
|
||||
let mut kind = 0;
|
||||
unsafe {
|
||||
let err = RegQueryValueExW(
|
||||
self.raw(),
|
||||
name.as_ptr(),
|
||||
null_mut(),
|
||||
&mut kind,
|
||||
null_mut(),
|
||||
&mut len,
|
||||
);
|
||||
if err != ERROR_SUCCESS {
|
||||
return Err(io::Error::from_raw_os_error(err as i32));
|
||||
}
|
||||
if kind != REG_SZ {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"registry key wasn't a string",
|
||||
));
|
||||
}
|
||||
|
||||
// The length here is the length in bytes, but we're using wide
|
||||
// characters so we need to be sure to halve it for the length
|
||||
// passed in.
|
||||
assert!(len % 2 == 0, "impossible wide string size: {} bytes", len);
|
||||
let vlen = len as usize / 2;
|
||||
// Defensively initialized, see comment about
|
||||
// `HKEY_PERFORMANCE_DATA` below.
|
||||
let mut v = vec![0u16; vlen];
|
||||
let err = RegQueryValueExW(
|
||||
self.raw(),
|
||||
name.as_ptr(),
|
||||
null_mut(),
|
||||
null_mut(),
|
||||
v.as_mut_ptr() as *mut _,
|
||||
&mut len,
|
||||
);
|
||||
// We don't check for `ERROR_MORE_DATA` (which would if the value
|
||||
// grew between the first and second call to `RegQueryValueExW`),
|
||||
// both because it's extremely unlikely, and this is a bit more
|
||||
// defensive more defensive against weird types of registry keys.
|
||||
if err != ERROR_SUCCESS {
|
||||
return Err(io::Error::from_raw_os_error(err as i32));
|
||||
}
|
||||
// The length is allowed to change, but should still be even, as
|
||||
// well as smaller.
|
||||
assert!(len % 2 == 0, "impossible wide string size: {} bytes", len);
|
||||
// If the length grew but returned a success code, it *probably*
|
||||
// indicates we're `HKEY_PERFORMANCE_DATA` or a subkey(?). We
|
||||
// consider this UB, since those keys write "undefined" or
|
||||
// "unpredictable" values to len, and need to use a completely
|
||||
// different loop structure. This should be impossible (and enforce
|
||||
// it in the API to the best of our ability), but to mitigate the
|
||||
// damage we do some smoke-checks on the len, and ensure `v` has
|
||||
// been fully initialized (rather than trusting the result of
|
||||
// `RegQueryValueExW`).
|
||||
let actual_len = len as usize / 2;
|
||||
assert!(actual_len <= v.len());
|
||||
v.truncate(actual_len);
|
||||
// Some registry keys may have a terminating nul character, but
|
||||
// we're not interested in that, so chop it off if it's there.
|
||||
if !v.is_empty() && v[v.len() - 1] == 0 {
|
||||
v.pop();
|
||||
}
|
||||
Ok(OsString::from_wide(&v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for OwnedKey {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
RegCloseKey(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = io::Result<OsString>;
|
||||
|
||||
fn next(&mut self) -> Option<io::Result<OsString>> {
|
||||
self.idx.next().and_then(|i| unsafe {
|
||||
let mut v = Vec::with_capacity(256);
|
||||
let mut len = v.capacity() as DWORD;
|
||||
let ret = RegEnumKeyExW(
|
||||
self.key.raw(),
|
||||
i,
|
||||
v.as_mut_ptr(),
|
||||
&mut len,
|
||||
null_mut(),
|
||||
null_mut(),
|
||||
null_mut(),
|
||||
null_mut(),
|
||||
);
|
||||
if ret == ERROR_NO_MORE_ITEMS {
|
||||
None
|
||||
} else if ret != ERROR_SUCCESS {
|
||||
Some(Err(io::Error::from_raw_os_error(ret as i32)))
|
||||
} else {
|
||||
v.set_len(len as usize);
|
||||
Some(Ok(OsString::from_wide(&v)))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
283
vendor/cc/src/windows/setup_config.rs
vendored
Normal file
283
vendor/cc/src/windows/setup_config.rs
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
// Copyright © 2017 winapi-rs developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
|
||||
// All files in the project carrying such notice may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(bad_style)]
|
||||
#![allow(unused)]
|
||||
|
||||
use crate::windows::{
|
||||
com::{BStr, ComPtr},
|
||||
winapi::{
|
||||
IUnknown, IUnknownVtbl, Interface, LCID, LPCOLESTR, LPCWSTR, LPFILETIME, LPSAFEARRAY,
|
||||
PULONGLONG, ULONG,
|
||||
},
|
||||
windows_sys::{CoCreateInstance, BSTR, CLSCTX_ALL, HRESULT, S_FALSE},
|
||||
};
|
||||
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
ptr::{null, null_mut},
|
||||
};
|
||||
|
||||
// Bindings to the Setup.Configuration stuff
|
||||
pub type InstanceState = u32;
|
||||
|
||||
pub const eNone: InstanceState = 0;
|
||||
pub const eLocal: InstanceState = 1;
|
||||
pub const eRegistered: InstanceState = 2;
|
||||
pub const eNoRebootRequired: InstanceState = 4;
|
||||
pub const eComplete: InstanceState = -1i32 as u32;
|
||||
|
||||
RIDL! {#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)]
|
||||
interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn GetInstanceId(
|
||||
pbstrInstanceId: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetInstallDate(
|
||||
pInstallDate: LPFILETIME,
|
||||
) -> HRESULT,
|
||||
fn GetInstallationName(
|
||||
pbstrInstallationName: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetInstallationPath(
|
||||
pbstrInstallationPath: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetInstallationVersion(
|
||||
pbstrInstallationVersion: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetDisplayName(
|
||||
lcid: LCID,
|
||||
pbstrDisplayName: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetDescription(
|
||||
lcid: LCID,
|
||||
pbstrDescription: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn ResolvePath(
|
||||
pwszRelativePath: LPCOLESTR,
|
||||
pbstrAbsolutePath: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL! {#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)]
|
||||
interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) {
|
||||
fn GetState(
|
||||
pState: *mut InstanceState,
|
||||
) -> HRESULT,
|
||||
fn GetPackages(
|
||||
ppsaPackages: *mut LPSAFEARRAY,
|
||||
) -> HRESULT,
|
||||
fn GetProduct(
|
||||
ppPackage: *mut *mut ISetupPackageReference,
|
||||
) -> HRESULT,
|
||||
fn GetProductPath(
|
||||
pbstrProductPath: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL! {#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)]
|
||||
interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn Next(
|
||||
celt: ULONG,
|
||||
rgelt: *mut *mut ISetupInstance,
|
||||
pceltFetched: *mut ULONG,
|
||||
) -> HRESULT,
|
||||
fn Skip(
|
||||
celt: ULONG,
|
||||
) -> HRESULT,
|
||||
fn Reset() -> HRESULT,
|
||||
fn Clone(
|
||||
ppenum: *mut *mut IEnumSetupInstances,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL! {#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)]
|
||||
interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn EnumInstances(
|
||||
ppEnumInstances: *mut *mut IEnumSetupInstances,
|
||||
) -> HRESULT,
|
||||
fn GetInstanceForCurrentProcess(
|
||||
ppInstance: *mut *mut ISetupInstance,
|
||||
) -> HRESULT,
|
||||
fn GetInstanceForPath(
|
||||
wzPath: LPCWSTR,
|
||||
ppInstance: *mut *mut ISetupInstance,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL! {#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)]
|
||||
interface ISetupConfiguration2(ISetupConfiguration2Vtbl):
|
||||
ISetupConfiguration(ISetupConfigurationVtbl) {
|
||||
fn EnumAllInstances(
|
||||
ppEnumInstances: *mut *mut IEnumSetupInstances,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL! {#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)]
|
||||
interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn GetId(
|
||||
pbstrId: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetVersion(
|
||||
pbstrVersion: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetChip(
|
||||
pbstrChip: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetLanguage(
|
||||
pbstrLanguage: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetBranch(
|
||||
pbstrBranch: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetType(
|
||||
pbstrType: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
fn GetUniqueId(
|
||||
pbstrUniqueId: *mut BSTR,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
RIDL! {#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)]
|
||||
interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) {
|
||||
fn ParseVersion(
|
||||
pwszVersion: LPCOLESTR,
|
||||
pullVersion: PULONGLONG,
|
||||
) -> HRESULT,
|
||||
fn ParseVersionRange(
|
||||
pwszVersionRange: LPCOLESTR,
|
||||
pullMinVersion: PULONGLONG,
|
||||
pullMaxVersion: PULONGLONG,
|
||||
) -> HRESULT,
|
||||
}}
|
||||
|
||||
DEFINE_GUID! {CLSID_SetupConfiguration,
|
||||
0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d}
|
||||
|
||||
// Safe wrapper around the COM interfaces
|
||||
pub struct SetupConfiguration(ComPtr<ISetupConfiguration>);
|
||||
|
||||
impl SetupConfiguration {
|
||||
pub fn new() -> Result<SetupConfiguration, i32> {
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe {
|
||||
CoCreateInstance(
|
||||
&CLSID_SetupConfiguration,
|
||||
null_mut(),
|
||||
CLSCTX_ALL,
|
||||
&ISetupConfiguration::uuidof(),
|
||||
&mut obj,
|
||||
)
|
||||
};
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) };
|
||||
Ok(SetupConfiguration(obj))
|
||||
}
|
||||
pub fn get_instance_for_current_process(&self) -> Result<SetupInstance, i32> {
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) };
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(unsafe { SetupInstance::from_raw(obj) })
|
||||
}
|
||||
pub fn enum_instances(&self) -> Result<EnumSetupInstances, i32> {
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe { self.0.EnumInstances(&mut obj) };
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(unsafe { EnumSetupInstances::from_raw(obj) })
|
||||
}
|
||||
pub fn enum_all_instances(&self) -> Result<EnumSetupInstances, i32> {
|
||||
let mut obj = null_mut();
|
||||
let this = self.0.cast::<ISetupConfiguration2>()?;
|
||||
let err = unsafe { this.EnumAllInstances(&mut obj) };
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(unsafe { EnumSetupInstances::from_raw(obj) })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SetupInstance(ComPtr<ISetupInstance>);
|
||||
|
||||
impl SetupInstance {
|
||||
pub unsafe fn from_raw(obj: *mut ISetupInstance) -> SetupInstance {
|
||||
SetupInstance(ComPtr::from_raw(obj))
|
||||
}
|
||||
pub fn instance_id(&self) -> Result<OsString, i32> {
|
||||
let mut s = null();
|
||||
let err = unsafe { self.0.GetInstanceId(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
pub fn installation_name(&self) -> Result<OsString, i32> {
|
||||
let mut s = null();
|
||||
let err = unsafe { self.0.GetInstallationName(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
pub fn installation_path(&self) -> Result<OsString, i32> {
|
||||
let mut s = null();
|
||||
let err = unsafe { self.0.GetInstallationPath(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
pub fn installation_version(&self) -> Result<OsString, i32> {
|
||||
let mut s = null();
|
||||
let err = unsafe { self.0.GetInstallationVersion(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
pub fn product_path(&self) -> Result<OsString, i32> {
|
||||
let mut s = null();
|
||||
let this = self.0.cast::<ISetupInstance2>()?;
|
||||
let err = unsafe { this.GetProductPath(&mut s) };
|
||||
let bstr = unsafe { BStr::from_raw(s) };
|
||||
if err < 0 {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(bstr.to_osstring())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EnumSetupInstances(ComPtr<IEnumSetupInstances>);
|
||||
|
||||
impl EnumSetupInstances {
|
||||
pub unsafe fn from_raw(obj: *mut IEnumSetupInstances) -> EnumSetupInstances {
|
||||
EnumSetupInstances(ComPtr::from_raw(obj))
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for EnumSetupInstances {
|
||||
type Item = Result<SetupInstance, i32>;
|
||||
fn next(&mut self) -> Option<Result<SetupInstance, i32>> {
|
||||
let mut obj = null_mut();
|
||||
let err = unsafe { self.0.Next(1, &mut obj, null_mut()) };
|
||||
if err < 0 {
|
||||
return Some(Err(err));
|
||||
}
|
||||
if err == S_FALSE {
|
||||
return None;
|
||||
}
|
||||
Some(Ok(unsafe { SetupInstance::from_raw(obj) }))
|
||||
}
|
||||
}
|
199
vendor/cc/src/windows/vs_instances.rs
vendored
Normal file
199
vendor/cc/src/windows/vs_instances.rs
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::io::BufRead;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::windows::setup_config::{EnumSetupInstances, SetupInstance};
|
||||
|
||||
pub enum VsInstance {
|
||||
Com(SetupInstance),
|
||||
Vswhere(VswhereInstance),
|
||||
}
|
||||
|
||||
impl VsInstance {
|
||||
pub fn installation_name(&self) -> Option<Cow<str>> {
|
||||
match self {
|
||||
VsInstance::Com(s) => s
|
||||
.installation_name()
|
||||
.ok()
|
||||
.and_then(|s| s.into_string().ok())
|
||||
.map(Cow::from),
|
||||
VsInstance::Vswhere(v) => v.map.get("installationName").map(Cow::from),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn installation_path(&self) -> Option<PathBuf> {
|
||||
match self {
|
||||
VsInstance::Com(s) => s.installation_path().ok().map(PathBuf::from),
|
||||
VsInstance::Vswhere(v) => v.map.get("installationPath").map(PathBuf::from),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn installation_version(&self) -> Option<Cow<str>> {
|
||||
match self {
|
||||
VsInstance::Com(s) => s
|
||||
.installation_version()
|
||||
.ok()
|
||||
.and_then(|s| s.into_string().ok())
|
||||
.map(Cow::from),
|
||||
VsInstance::Vswhere(v) => v.map.get("installationVersion").map(Cow::from),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum VsInstances {
|
||||
ComBased(EnumSetupInstances),
|
||||
VswhereBased(VswhereInstance),
|
||||
}
|
||||
|
||||
impl IntoIterator for VsInstances {
|
||||
type Item = VsInstance;
|
||||
#[allow(bare_trait_objects)]
|
||||
type IntoIter = Box<Iterator<Item = Self::Item>>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
match self {
|
||||
VsInstances::ComBased(e) => {
|
||||
Box::new(e.into_iter().filter_map(Result::ok).map(VsInstance::Com))
|
||||
}
|
||||
VsInstances::VswhereBased(v) => Box::new(std::iter::once(VsInstance::Vswhere(v))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VswhereInstance {
|
||||
map: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl TryFrom<&Vec<u8>> for VswhereInstance {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(output: &Vec<u8>) -> Result<Self, Self::Error> {
|
||||
let map: HashMap<_, _> = output
|
||||
.lines()
|
||||
.map_while(Result::ok)
|
||||
.filter_map(|s| {
|
||||
let mut splitn = s.splitn(2, ": ");
|
||||
Some((splitn.next()?.to_owned(), splitn.next()?.to_owned()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !map.contains_key("installationName")
|
||||
|| !map.contains_key("installationPath")
|
||||
|| !map.contains_key("installationVersion")
|
||||
{
|
||||
return Err("required properties not found");
|
||||
}
|
||||
|
||||
Ok(Self { map })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests_ {
|
||||
use std::borrow::Cow;
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn it_parses_vswhere_output_correctly() {
|
||||
let output = br"instanceId: 58104422
|
||||
installDate: 21/02/2021 21:50:33
|
||||
installationName: VisualStudio/16.9.2+31112.23
|
||||
installationPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools
|
||||
installationVersion: 16.9.31112.23
|
||||
productId: Microsoft.VisualStudio.Product.BuildTools
|
||||
productPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\LaunchDevCmd.bat
|
||||
state: 4294967295
|
||||
isComplete: 1
|
||||
isLaunchable: 1
|
||||
isPrerelease: 0
|
||||
isRebootRequired: 0
|
||||
displayName: Visual Studio Build Tools 2019
|
||||
description: The Visual Studio Build Tools allows you to build native and managed MSBuild-based applications without requiring the Visual Studio IDE. There are options to install the Visual C++ compilers and libraries, MFC, ATL, and C++/CLI support.
|
||||
channelId: VisualStudio.16.Release
|
||||
channelUri: https://aka.ms/vs/16/release/channel
|
||||
enginePath: C:\Program Files (x86)\Microsoft Visual Studio\Installer\resources\app\ServiceHub\Services\Microsoft.VisualStudio.Setup.Service
|
||||
releaseNotes: https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-v16.9#16.9.2
|
||||
thirdPartyNotices: https://go.microsoft.com/fwlink/?LinkId=660909
|
||||
updateDate: 2021-03-17T21:16:46.5963702Z
|
||||
catalog_buildBranch: d16.9
|
||||
catalog_buildVersion: 16.9.31112.23
|
||||
catalog_id: VisualStudio/16.9.2+31112.23
|
||||
catalog_localBuild: build-lab
|
||||
catalog_manifestName: VisualStudio
|
||||
catalog_manifestType: installer
|
||||
catalog_productDisplayVersion: 16.9.2
|
||||
catalog_productLine: Dev16
|
||||
catalog_productLineVersion: 2019
|
||||
catalog_productMilestone: RTW
|
||||
catalog_productMilestoneIsPreRelease: False
|
||||
catalog_productName: Visual Studio
|
||||
catalog_productPatchVersion: 2
|
||||
catalog_productPreReleaseMilestoneSuffix: 1.0
|
||||
catalog_productSemanticVersion: 16.9.2+31112.23
|
||||
catalog_requiredEngineVersion: 2.9.3365.38425
|
||||
properties_campaignId: 156063665.1613940062
|
||||
properties_channelManifestId: VisualStudio.16.Release/16.9.2+31112.23
|
||||
properties_nickname:
|
||||
properties_setupEngineFilePath: C:\Program Files (x86)\Microsoft Visual Studio\Installer\vs_installershell.exe
|
||||
"
|
||||
.to_vec();
|
||||
|
||||
let vswhere_instance = super::VswhereInstance::try_from(&output);
|
||||
assert!(vswhere_instance.is_ok());
|
||||
|
||||
let vs_instance = super::VsInstance::Vswhere(vswhere_instance.unwrap());
|
||||
assert_eq!(
|
||||
vs_instance.installation_name(),
|
||||
Some(Cow::from("VisualStudio/16.9.2+31112.23"))
|
||||
);
|
||||
assert_eq!(
|
||||
vs_instance.installation_path(),
|
||||
Some(PathBuf::from(
|
||||
r"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools"
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
vs_instance.installation_version(),
|
||||
Some(Cow::from("16.9.31112.23"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_returns_an_error_for_empty_output() {
|
||||
let output = b"".to_vec();
|
||||
|
||||
let vswhere_instance = super::VswhereInstance::try_from(&output);
|
||||
|
||||
assert!(vswhere_instance.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_returns_an_error_for_output_consisting_of_empty_lines() {
|
||||
let output = br"
|
||||
|
||||
"
|
||||
.to_vec();
|
||||
|
||||
let vswhere_instance = super::VswhereInstance::try_from(&output);
|
||||
|
||||
assert!(vswhere_instance.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_returns_an_error_for_output_without_required_properties() {
|
||||
let output = br"instanceId: 58104422
|
||||
installDate: 21/02/2021 21:50:33
|
||||
productId: Microsoft.VisualStudio.Product.BuildTools
|
||||
productPath: C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\LaunchDevCmd.bat
|
||||
"
|
||||
.to_vec();
|
||||
|
||||
let vswhere_instance = super::VswhereInstance::try_from(&output);
|
||||
|
||||
assert!(vswhere_instance.is_err());
|
||||
}
|
||||
}
|
146
vendor/cc/src/windows/winapi.rs
vendored
Normal file
146
vendor/cc/src/windows/winapi.rs
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright © 2015-2017 winapi-rs developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
|
||||
// All files in the project carrying such notice may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(bad_style, clippy::upper_case_acronyms)]
|
||||
|
||||
use std::os::raw;
|
||||
|
||||
pub type wchar_t = u16;
|
||||
|
||||
pub use crate::windows::windows_sys::{FILETIME, GUID, HRESULT, SAFEARRAY};
|
||||
|
||||
pub type REFIID = *const IID;
|
||||
pub type IID = GUID;
|
||||
pub type ULONG = raw::c_ulong;
|
||||
pub type DWORD = u32;
|
||||
pub type LPFILETIME = *mut FILETIME;
|
||||
pub type OLECHAR = WCHAR;
|
||||
pub type WCHAR = wchar_t;
|
||||
pub type LPCOLESTR = *const OLECHAR;
|
||||
pub type LCID = DWORD;
|
||||
pub type LPCWSTR = *const WCHAR;
|
||||
pub type PULONGLONG = *mut ULONGLONG;
|
||||
pub type ULONGLONG = u64;
|
||||
|
||||
pub trait Interface {
|
||||
fn uuidof() -> GUID;
|
||||
}
|
||||
|
||||
pub type LPSAFEARRAY = *mut SAFEARRAY;
|
||||
|
||||
macro_rules! DEFINE_GUID {
|
||||
(
|
||||
$name:ident, $l:expr, $w1:expr, $w2:expr,
|
||||
$b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
|
||||
) => {
|
||||
pub const $name: $crate::windows::winapi::GUID = $crate::windows::winapi::GUID {
|
||||
data1: $l,
|
||||
data2: $w1,
|
||||
data3: $w2,
|
||||
data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! RIDL {
|
||||
(#[uuid($($uuid:expr),+)]
|
||||
interface $interface:ident ($vtbl:ident) {$(
|
||||
fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
|
||||
)+}) => (
|
||||
#[repr(C)]
|
||||
pub struct $vtbl {
|
||||
$(pub $method: unsafe extern "system" fn(
|
||||
This: *mut $interface,
|
||||
$($p: $t),*
|
||||
) -> $rtr,)+
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct $interface {
|
||||
pub lpVtbl: *const $vtbl,
|
||||
}
|
||||
RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
|
||||
RIDL!{@uuid $interface $($uuid),+}
|
||||
);
|
||||
(#[uuid($($uuid:expr),+)]
|
||||
interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {
|
||||
}) => (
|
||||
#[repr(C)]
|
||||
pub struct $vtbl {
|
||||
pub parent: $pvtbl,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct $interface {
|
||||
pub lpVtbl: *const $vtbl,
|
||||
}
|
||||
RIDL!{@deref $interface $pinterface}
|
||||
RIDL!{@uuid $interface $($uuid),+}
|
||||
);
|
||||
(#[uuid($($uuid:expr),+)]
|
||||
interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$(
|
||||
fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
|
||||
)+}) => (
|
||||
#[repr(C)]
|
||||
pub struct $vtbl {
|
||||
pub parent: $pvtbl,
|
||||
$(pub $method: unsafe extern "system" fn(
|
||||
This: *mut $interface,
|
||||
$($p: $t,)*
|
||||
) -> $rtr,)+
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct $interface {
|
||||
pub lpVtbl: *const $vtbl,
|
||||
}
|
||||
RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}}
|
||||
RIDL!{@deref $interface $pinterface}
|
||||
RIDL!{@uuid $interface $($uuid),+}
|
||||
);
|
||||
(@deref $interface:ident $pinterface:ident) => (
|
||||
impl ::std::ops::Deref for $interface {
|
||||
type Target = $pinterface;
|
||||
#[inline]
|
||||
fn deref(&self) -> &$pinterface {
|
||||
unsafe { &*(self as *const $interface as *const $pinterface) }
|
||||
}
|
||||
}
|
||||
);
|
||||
(@impl $interface:ident {$(
|
||||
fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,
|
||||
)+}) => (
|
||||
impl $interface {
|
||||
$(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr {
|
||||
((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*)
|
||||
})+
|
||||
}
|
||||
);
|
||||
(@uuid $interface:ident
|
||||
$l:expr, $w1:expr, $w2:expr,
|
||||
$b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr
|
||||
) => (
|
||||
impl $crate::windows::winapi::Interface for $interface {
|
||||
#[inline]
|
||||
fn uuidof() -> $crate::windows::winapi::GUID {
|
||||
$crate::windows::winapi::GUID {
|
||||
data1: $l,
|
||||
data2: $w1,
|
||||
data3: $w2,
|
||||
data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8],
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
RIDL! {#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)]
|
||||
interface IUnknown(IUnknownVtbl) {
|
||||
fn QueryInterface(
|
||||
riid: REFIID,
|
||||
ppvObject: *mut *mut raw::c_void,
|
||||
) -> HRESULT,
|
||||
fn AddRef() -> ULONG,
|
||||
fn Release() -> ULONG,
|
||||
}}
|
205
vendor/cc/src/windows/windows_sys.rs
vendored
Normal file
205
vendor/cc/src/windows/windows_sys.rs
vendored
Normal file
@ -0,0 +1,205 @@
|
||||
// This file is autogenerated.
|
||||
//
|
||||
// To add bindings, edit windows_sys.lst then run:
|
||||
//
|
||||
// ```
|
||||
// cd generate-windows-sys/
|
||||
// cargo run
|
||||
// ```
|
||||
// Bindings generated by `windows-bindgen` 0.57.0
|
||||
|
||||
#![allow(
|
||||
non_snake_case,
|
||||
non_upper_case_globals,
|
||||
non_camel_case_types,
|
||||
dead_code,
|
||||
clippy::all
|
||||
)]
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
pub fn RegCloseKey(hkey: HKEY) -> WIN32_ERROR;
|
||||
}
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
pub fn RegEnumKeyExW(
|
||||
hkey: HKEY,
|
||||
dwindex: u32,
|
||||
lpname: PWSTR,
|
||||
lpcchname: *mut u32,
|
||||
lpreserved: *const u32,
|
||||
lpclass: PWSTR,
|
||||
lpcchclass: *mut u32,
|
||||
lpftlastwritetime: *mut FILETIME,
|
||||
) -> WIN32_ERROR;
|
||||
}
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
pub fn RegOpenKeyExW(
|
||||
hkey: HKEY,
|
||||
lpsubkey: PCWSTR,
|
||||
uloptions: u32,
|
||||
samdesired: REG_SAM_FLAGS,
|
||||
phkresult: *mut HKEY,
|
||||
) -> WIN32_ERROR;
|
||||
}
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
pub fn RegQueryValueExW(
|
||||
hkey: HKEY,
|
||||
lpvaluename: PCWSTR,
|
||||
lpreserved: *const u32,
|
||||
lptype: *mut REG_VALUE_TYPE,
|
||||
lpdata: *mut u8,
|
||||
lpcbdata: *mut u32,
|
||||
) -> WIN32_ERROR;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn FreeLibrary(hlibmodule: HMODULE) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetMachineTypeAttributes(
|
||||
machine: u16,
|
||||
machinetypeattributes: *mut MACHINE_ATTRIBUTES,
|
||||
) -> HRESULT;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn GetProcAddress(hmodule: HMODULE, lpprocname: PCSTR) -> FARPROC;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn LoadLibraryA(lplibfilename: PCSTR) -> HMODULE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn OpenSemaphoreA(dwdesiredaccess: u32, binherithandle: BOOL, lpname: PCSTR) -> HANDLE;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn PeekNamedPipe(
|
||||
hnamedpipe: HANDLE,
|
||||
lpbuffer: *mut core::ffi::c_void,
|
||||
nbuffersize: u32,
|
||||
lpbytesread: *mut u32,
|
||||
lptotalbytesavail: *mut u32,
|
||||
lpbytesleftthismessage: *mut u32,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn ReleaseSemaphore(
|
||||
hsemaphore: HANDLE,
|
||||
lreleasecount: i32,
|
||||
lppreviouscount: *mut i32,
|
||||
) -> BOOL;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
pub fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> WAIT_EVENT;
|
||||
}
|
||||
#[link(name = "ole32")]
|
||||
extern "system" {
|
||||
pub fn CoCreateInstance(
|
||||
rclsid: *const GUID,
|
||||
punkouter: *mut core::ffi::c_void,
|
||||
dwclscontext: CLSCTX,
|
||||
riid: *const GUID,
|
||||
ppv: *mut *mut core::ffi::c_void,
|
||||
) -> HRESULT;
|
||||
}
|
||||
#[link(name = "ole32")]
|
||||
extern "system" {
|
||||
pub fn CoInitializeEx(pvreserved: *const core::ffi::c_void, dwcoinit: u32) -> HRESULT;
|
||||
}
|
||||
#[link(name = "oleaut32")]
|
||||
extern "system" {
|
||||
pub fn SysFreeString(bstrstring: BSTR);
|
||||
}
|
||||
#[link(name = "oleaut32")]
|
||||
extern "system" {
|
||||
pub fn SysStringLen(pbstr: BSTR) -> u32;
|
||||
}
|
||||
pub type ADVANCED_FEATURE_FLAGS = u16;
|
||||
pub type BOOL = i32;
|
||||
pub type BSTR = *const u16;
|
||||
pub type CLSCTX = u32;
|
||||
pub const CLSCTX_ALL: CLSCTX = 23u32;
|
||||
pub type COINIT = i32;
|
||||
pub const COINIT_MULTITHREADED: COINIT = 0i32;
|
||||
pub const ERROR_NO_MORE_ITEMS: WIN32_ERROR = 259u32;
|
||||
pub const ERROR_SUCCESS: WIN32_ERROR = 0u32;
|
||||
pub const FALSE: BOOL = 0i32;
|
||||
pub type FARPROC = Option<unsafe extern "system" fn() -> isize>;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FILETIME {
|
||||
pub dwLowDateTime: u32,
|
||||
pub dwHighDateTime: u32,
|
||||
}
|
||||
pub const FILE_ATTRIBUTE_TEMPORARY: FILE_FLAGS_AND_ATTRIBUTES = 256u32;
|
||||
pub type FILE_FLAGS_AND_ATTRIBUTES = u32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct GUID {
|
||||
pub data1: u32,
|
||||
pub data2: u16,
|
||||
pub data3: u16,
|
||||
pub data4: [u8; 8],
|
||||
}
|
||||
impl GUID {
|
||||
pub const fn from_u128(uuid: u128) -> Self {
|
||||
Self {
|
||||
data1: (uuid >> 96) as u32,
|
||||
data2: (uuid >> 80 & 0xffff) as u16,
|
||||
data3: (uuid >> 64 & 0xffff) as u16,
|
||||
data4: (uuid as u64).to_be_bytes(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type HANDLE = *mut core::ffi::c_void;
|
||||
pub type HKEY = *mut core::ffi::c_void;
|
||||
pub const HKEY_LOCAL_MACHINE: HKEY = -2147483646i32 as _;
|
||||
pub type HMODULE = *mut core::ffi::c_void;
|
||||
pub type HRESULT = i32;
|
||||
pub type IMAGE_FILE_MACHINE = u16;
|
||||
pub const IMAGE_FILE_MACHINE_AMD64: IMAGE_FILE_MACHINE = 34404u16;
|
||||
pub const KEY_READ: REG_SAM_FLAGS = 131097u32;
|
||||
pub const KEY_WOW64_32KEY: REG_SAM_FLAGS = 512u32;
|
||||
pub type MACHINE_ATTRIBUTES = i32;
|
||||
pub type PCSTR = *const u8;
|
||||
pub type PCWSTR = *const u16;
|
||||
pub type PWSTR = *mut u16;
|
||||
pub type REG_SAM_FLAGS = u32;
|
||||
pub const REG_SZ: REG_VALUE_TYPE = 1u32;
|
||||
pub type REG_VALUE_TYPE = u32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SAFEARRAY {
|
||||
pub cDims: u16,
|
||||
pub fFeatures: ADVANCED_FEATURE_FLAGS,
|
||||
pub cbElements: u32,
|
||||
pub cLocks: u32,
|
||||
pub pvData: *mut core::ffi::c_void,
|
||||
pub rgsabound: [SAFEARRAYBOUND; 1],
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SAFEARRAYBOUND {
|
||||
pub cElements: u32,
|
||||
pub lLbound: i32,
|
||||
}
|
||||
pub const SEMAPHORE_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32;
|
||||
pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32;
|
||||
pub const S_FALSE: HRESULT = 0x1_u32 as _;
|
||||
pub const S_OK: HRESULT = 0x0_u32 as _;
|
||||
pub type THREAD_ACCESS_RIGHTS = u32;
|
||||
pub const THREAD_SYNCHRONIZE: THREAD_ACCESS_RIGHTS = 1048576u32;
|
||||
pub const UserEnabled: MACHINE_ATTRIBUTES = 1i32;
|
||||
pub const WAIT_ABANDONED: WAIT_EVENT = 128u32;
|
||||
pub type WAIT_EVENT = u32;
|
||||
pub const WAIT_FAILED: WAIT_EVENT = 4294967295u32;
|
||||
pub const WAIT_OBJECT_0: WAIT_EVENT = 0u32;
|
||||
pub const WAIT_TIMEOUT: WAIT_EVENT = 258u32;
|
||||
pub type WIN32_ERROR = u32;
|
1
vendor/either/.cargo-checksum.json
vendored
Normal file
1
vendor/either/.cargo-checksum.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"aa34836ecfe961a4675ba7b0b9a65fc710d8d89ab6e570ea8c048a0c93abc3b2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README-crates.io.md":"b775991a01ab4a0a8de6169f597775319d9ce8178f5c74ccdc634f13a286b20c","README.rst":"39afa0feb4705fc962aaa2284a4d82c7f64fa05ee9412dfd5e762a3fdeaef6f0","src/into_either.rs":"0477f226bbba78ef017de08b87d421d3cd99fbc95b90ba4e6e3e803e3d15254e","src/iterator.rs":"fa2a6d14141980ce8a0bfcf7df2113d1e056d0f9815773dc9c2fb92a88923f4a","src/lib.rs":"a3f9f520d5f62cddf82495c6baca0c25081dfc5f12e2c352378910734a39798e","src/serde_untagged.rs":"e826ee0ab31616e49c3e3f3711c8441001ee424b3e7a8c4c466cfcc4f8a7701a","src/serde_untagged_optional.rs":"86265f09d0795428bb2ce013b070d1badf1e2210217844a9ff3f04b2795868ab"},"package":"60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"}
|
54
vendor/either/Cargo.toml
vendored
Normal file
54
vendor/either/Cargo.toml
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
rust-version = "1.37"
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
authors = ["bluss"]
|
||||
description = """
|
||||
The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases.
|
||||
"""
|
||||
documentation = "https://docs.rs/either/1/"
|
||||
readme = "README-crates.io.md"
|
||||
keywords = [
|
||||
"data-structure",
|
||||
"no_std",
|
||||
]
|
||||
categories = [
|
||||
"data-structures",
|
||||
"no-std",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rayon-rs/either"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["serde"]
|
||||
|
||||
[package.metadata.playground]
|
||||
features = ["serde"]
|
||||
|
||||
[package.metadata.release]
|
||||
no-dev-version = true
|
||||
tag-name = "{{version}}"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
features = ["derive"]
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.serde_json]
|
||||
version = "1.0.0"
|
||||
|
||||
[features]
|
||||
default = ["use_std"]
|
||||
use_std = []
|
201
vendor/either/LICENSE-APACHE
vendored
Normal file
201
vendor/either/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
25
vendor/either/LICENSE-MIT
vendored
Normal file
25
vendor/either/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
Copyright (c) 2015
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
10
vendor/either/README-crates.io.md
vendored
Normal file
10
vendor/either/README-crates.io.md
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
The enum `Either` with variants `Left` and `Right` is a general purpose
|
||||
sum type with two cases.
|
||||
|
||||
Either has methods that are similar to Option and Result, and it also implements
|
||||
traits like `Iterator`.
|
||||
|
||||
Includes macros `try_left!()` and `try_right!()` to use for
|
||||
short-circuiting logic, similar to how the `?` operator is used with `Result`.
|
||||
Note that `Either` is general purpose. For describing success or error, use the
|
||||
regular `Result`.
|
189
vendor/either/README.rst
vendored
Normal file
189
vendor/either/README.rst
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
|
||||
Either
|
||||
======
|
||||
|
||||
The enum ``Either`` with variants ``Left`` and ``Right`` and trait
|
||||
implementations including Iterator, Read, Write.
|
||||
|
||||
Either has methods that are similar to Option and Result.
|
||||
|
||||
Includes convenience macros ``try_left!()`` and ``try_right!()`` to use for
|
||||
short-circuiting logic.
|
||||
|
||||
Please read the `API documentation here`__
|
||||
|
||||
__ https://docs.rs/either/
|
||||
|
||||
|build_status|_ |crates|_
|
||||
|
||||
.. |build_status| image:: https://github.com/rayon-rs/either/workflows/CI/badge.svg?branch=main
|
||||
.. _build_status: https://github.com/rayon-rs/either/actions
|
||||
|
||||
.. |crates| image:: https://img.shields.io/crates/v/either.svg
|
||||
.. _crates: https://crates.io/crates/either
|
||||
|
||||
How to use with cargo::
|
||||
|
||||
[dependencies]
|
||||
either = "1.12"
|
||||
|
||||
|
||||
Recent Changes
|
||||
--------------
|
||||
|
||||
- 1.13.0
|
||||
|
||||
- Add new methods ``.cloned()`` and ``.copied()``, by @ColonelThirtyTwo (#107)
|
||||
|
||||
- 1.12.0
|
||||
|
||||
- **MSRV**: ``either`` now requires Rust 1.37 or later.
|
||||
|
||||
- Specialize ``nth_back`` for ``Either`` and ``IterEither``, by @cuviper (#106)
|
||||
|
||||
- 1.11.0
|
||||
|
||||
- Add new trait ``IntoEither`` that is useful to convert to ``Either`` in method chains,
|
||||
by @SFM61319 (#101)
|
||||
|
||||
- 1.10.0
|
||||
|
||||
- Add new methods ``.factor_iter()``, ``.factor_iter_mut()``, and ``.factor_into_iter()``
|
||||
that return ``Either`` items, plus ``.iter()`` and ``.iter_mut()`` to convert to direct
|
||||
referene iterators; by @aj-bagwell and @cuviper (#91)
|
||||
|
||||
- 1.9.0
|
||||
|
||||
- Add new methods ``.map_either()`` and ``.map_either_with()``, by @nasadorian (#82)
|
||||
|
||||
- 1.8.1
|
||||
|
||||
- Clarified that the multiple licenses are combined with OR.
|
||||
|
||||
- 1.8.0
|
||||
|
||||
- **MSRV**: ``either`` now requires Rust 1.36 or later.
|
||||
|
||||
- Add new methods ``.as_pin_ref()`` and ``.as_pin_mut()`` to project a
|
||||
pinned ``Either`` as inner ``Pin`` variants, by @cuviper (#77)
|
||||
|
||||
- Implement the ``Future`` trait, by @cuviper (#77)
|
||||
|
||||
- Specialize more methods of the ``io`` traits, by @Kixunil and @cuviper (#75)
|
||||
|
||||
- 1.7.0
|
||||
|
||||
- **MSRV**: ``either`` now requires Rust 1.31 or later.
|
||||
|
||||
- Export the macro ``for_both!``, by @thomaseizinger (#58)
|
||||
|
||||
- Implement the ``io::Seek`` trait, by @Kerollmops (#60)
|
||||
|
||||
- Add new method ``.either_into()`` for ``Into`` conversion, by @TonalidadeHidrica (#63)
|
||||
|
||||
- Add new methods ``.factor_ok()``, ``.factor_err()``, and ``.factor_none()``,
|
||||
by @zachs18 (#67)
|
||||
|
||||
- Specialize ``source`` in the ``Error`` implementation, by @thomaseizinger (#69)
|
||||
|
||||
- Specialize more iterator methods and implement the ``FusedIterator`` trait,
|
||||
by @Ten0 (#66) and @cuviper (#71)
|
||||
|
||||
- Specialize ``Clone::clone_from``, by @cuviper (#72)
|
||||
|
||||
- 1.6.1
|
||||
|
||||
- Add new methods ``.expect_left()``, ``.unwrap_left()``,
|
||||
and equivalents on the right, by @spenserblack (#51)
|
||||
|
||||
- 1.6.0
|
||||
|
||||
- Add new modules ``serde_untagged`` and ``serde_untagged_optional`` to customize
|
||||
how ``Either`` fields are serialized in other types, by @MikailBag (#49)
|
||||
|
||||
- 1.5.3
|
||||
|
||||
- Add new method ``.map()`` for ``Either<T, T>`` by @nvzqz (#40).
|
||||
|
||||
- 1.5.2
|
||||
|
||||
- Add new methods ``.left_or()``, ``.left_or_default()``, ``.left_or_else()``,
|
||||
and equivalents on the right, by @DCjanus (#36)
|
||||
|
||||
- 1.5.1
|
||||
|
||||
- Add ``AsRef`` and ``AsMut`` implementations for common unsized types:
|
||||
``str``, ``[T]``, ``CStr``, ``OsStr``, and ``Path``, by @mexus (#29)
|
||||
|
||||
- 1.5.0
|
||||
|
||||
- Add new methods ``.factor_first()``, ``.factor_second()`` and ``.into_inner()``
|
||||
by @mathstuf (#19)
|
||||
|
||||
- 1.4.0
|
||||
|
||||
- Add inherent method ``.into_iter()`` by @cuviper (#12)
|
||||
|
||||
- 1.3.0
|
||||
|
||||
- Add opt-in serde support by @hcpl
|
||||
|
||||
- 1.2.0
|
||||
|
||||
- Add method ``.either_with()`` by @Twey (#13)
|
||||
|
||||
- 1.1.0
|
||||
|
||||
- Add methods ``left_and_then``, ``right_and_then`` by @rampantmonkey
|
||||
- Include license files in the repository and released crate
|
||||
|
||||
- 1.0.3
|
||||
|
||||
- Add crate categories
|
||||
|
||||
- 1.0.2
|
||||
|
||||
- Forward more ``Iterator`` methods
|
||||
- Implement ``Extend`` for ``Either<L, R>`` if ``L, R`` do.
|
||||
|
||||
- 1.0.1
|
||||
|
||||
- Fix ``Iterator`` impl for ``Either`` to forward ``.fold()``.
|
||||
|
||||
- 1.0.0
|
||||
|
||||
- Add default crate feature ``use_std`` so that you can opt out of linking to
|
||||
std.
|
||||
|
||||
- 0.1.7
|
||||
|
||||
- Add methods ``.map_left()``, ``.map_right()`` and ``.either()``.
|
||||
- Add more documentation
|
||||
|
||||
- 0.1.3
|
||||
|
||||
- Implement Display, Error
|
||||
|
||||
- 0.1.2
|
||||
|
||||
- Add macros ``try_left!`` and ``try_right!``.
|
||||
|
||||
- 0.1.1
|
||||
|
||||
- Implement Deref, DerefMut
|
||||
|
||||
- 0.1.0
|
||||
|
||||
- Initial release
|
||||
- Support Iterator, Read, Write
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Dual-licensed to be compatible with the Rust project.
|
||||
|
||||
Licensed under the Apache License, Version 2.0
|
||||
https://www.apache.org/licenses/LICENSE-2.0 or the MIT license
|
||||
https://opensource.org/licenses/MIT, at your
|
||||
option. This file may not be copied, modified, or distributed
|
||||
except according to those terms.
|
64
vendor/either/src/into_either.rs
vendored
Normal file
64
vendor/either/src/into_either.rs
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
//! The trait [`IntoEither`] provides methods for converting a type `Self`, whose
|
||||
//! size is constant and known at compile-time, into an [`Either`] variant.
|
||||
|
||||
use super::{Either, Left, Right};
|
||||
|
||||
/// Provides methods for converting a type `Self` into either a [`Left`] or [`Right`]
|
||||
/// variant of [`Either<Self, Self>`](Either).
|
||||
///
|
||||
/// The [`into_either`](IntoEither::into_either) method takes a [`bool`] to determine
|
||||
/// whether to convert to [`Left`] or [`Right`].
|
||||
///
|
||||
/// The [`into_either_with`](IntoEither::into_either_with) method takes a
|
||||
/// [predicate function](FnOnce) to determine whether to convert to [`Left`] or [`Right`].
|
||||
pub trait IntoEither: Sized {
|
||||
/// Converts `self` into a [`Left`] variant of [`Either<Self, Self>`](Either)
|
||||
/// if `into_left` is `true`.
|
||||
/// Converts `self` into a [`Right`] variant of [`Either<Self, Self>`](Either)
|
||||
/// otherwise.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use either::{IntoEither, Left, Right};
|
||||
///
|
||||
/// let x = 0;
|
||||
/// assert_eq!(x.into_either(true), Left(x));
|
||||
/// assert_eq!(x.into_either(false), Right(x));
|
||||
/// ```
|
||||
fn into_either(self, into_left: bool) -> Either<Self, Self> {
|
||||
if into_left {
|
||||
Left(self)
|
||||
} else {
|
||||
Right(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts `self` into a [`Left`] variant of [`Either<Self, Self>`](Either)
|
||||
/// if `into_left(&self)` returns `true`.
|
||||
/// Converts `self` into a [`Right`] variant of [`Either<Self, Self>`](Either)
|
||||
/// otherwise.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use either::{IntoEither, Left, Right};
|
||||
///
|
||||
/// fn is_even(x: &u8) -> bool {
|
||||
/// x % 2 == 0
|
||||
/// }
|
||||
///
|
||||
/// let x = 0;
|
||||
/// assert_eq!(x.into_either_with(is_even), Left(x));
|
||||
/// assert_eq!(x.into_either_with(|x| !is_even(x)), Right(x));
|
||||
/// ```
|
||||
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
|
||||
where
|
||||
F: FnOnce(&Self) -> bool,
|
||||
{
|
||||
let into_left = into_left(&self);
|
||||
self.into_either(into_left)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoEither for T {}
|
315
vendor/either/src/iterator.rs
vendored
Normal file
315
vendor/either/src/iterator.rs
vendored
Normal file
@ -0,0 +1,315 @@
|
||||
use super::{for_both, Either, Left, Right};
|
||||
use core::iter;
|
||||
|
||||
macro_rules! wrap_either {
|
||||
($value:expr => $( $tail:tt )*) => {
|
||||
match $value {
|
||||
Left(inner) => inner.map(Left) $($tail)*,
|
||||
Right(inner) => inner.map(Right) $($tail)*,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Iterator that maps left or right iterators to corresponding `Either`-wrapped items.
|
||||
///
|
||||
/// This struct is created by the [`Either::factor_into_iter`],
|
||||
/// [`factor_iter`][Either::factor_iter],
|
||||
/// and [`factor_iter_mut`][Either::factor_iter_mut] methods.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IterEither<L, R> {
|
||||
inner: Either<L, R>,
|
||||
}
|
||||
|
||||
impl<L, R> IterEither<L, R> {
|
||||
pub(crate) fn new(inner: Either<L, R>) -> Self {
|
||||
IterEither { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R, A> Extend<A> for Either<L, R>
|
||||
where
|
||||
L: Extend<A>,
|
||||
R: Extend<A>,
|
||||
{
|
||||
fn extend<T>(&mut self, iter: T)
|
||||
where
|
||||
T: IntoIterator<Item = A>,
|
||||
{
|
||||
for_both!(*self, ref mut inner => inner.extend(iter))
|
||||
}
|
||||
}
|
||||
|
||||
/// `Either<L, R>` is an iterator if both `L` and `R` are iterators.
|
||||
impl<L, R> Iterator for Either<L, R>
|
||||
where
|
||||
L: Iterator,
|
||||
R: Iterator<Item = L::Item>,
|
||||
{
|
||||
type Item = L::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
for_both!(*self, ref mut inner => inner.next())
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
for_both!(*self, ref inner => inner.size_hint())
|
||||
}
|
||||
|
||||
fn fold<Acc, G>(self, init: Acc, f: G) -> Acc
|
||||
where
|
||||
G: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
for_both!(self, inner => inner.fold(init, f))
|
||||
}
|
||||
|
||||
fn for_each<F>(self, f: F)
|
||||
where
|
||||
F: FnMut(Self::Item),
|
||||
{
|
||||
for_both!(self, inner => inner.for_each(f))
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
for_both!(self, inner => inner.count())
|
||||
}
|
||||
|
||||
fn last(self) -> Option<Self::Item> {
|
||||
for_both!(self, inner => inner.last())
|
||||
}
|
||||
|
||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||
for_both!(*self, ref mut inner => inner.nth(n))
|
||||
}
|
||||
|
||||
fn collect<B>(self) -> B
|
||||
where
|
||||
B: iter::FromIterator<Self::Item>,
|
||||
{
|
||||
for_both!(self, inner => inner.collect())
|
||||
}
|
||||
|
||||
fn partition<B, F>(self, f: F) -> (B, B)
|
||||
where
|
||||
B: Default + Extend<Self::Item>,
|
||||
F: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
for_both!(self, inner => inner.partition(f))
|
||||
}
|
||||
|
||||
fn all<F>(&mut self, f: F) -> bool
|
||||
where
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
for_both!(*self, ref mut inner => inner.all(f))
|
||||
}
|
||||
|
||||
fn any<F>(&mut self, f: F) -> bool
|
||||
where
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
for_both!(*self, ref mut inner => inner.any(f))
|
||||
}
|
||||
|
||||
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where
|
||||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
for_both!(*self, ref mut inner => inner.find(predicate))
|
||||
}
|
||||
|
||||
fn find_map<B, F>(&mut self, f: F) -> Option<B>
|
||||
where
|
||||
F: FnMut(Self::Item) -> Option<B>,
|
||||
{
|
||||
for_both!(*self, ref mut inner => inner.find_map(f))
|
||||
}
|
||||
|
||||
fn position<P>(&mut self, predicate: P) -> Option<usize>
|
||||
where
|
||||
P: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
for_both!(*self, ref mut inner => inner.position(predicate))
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> DoubleEndedIterator for Either<L, R>
|
||||
where
|
||||
L: DoubleEndedIterator,
|
||||
R: DoubleEndedIterator<Item = L::Item>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
for_both!(*self, ref mut inner => inner.next_back())
|
||||
}
|
||||
|
||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
||||
for_both!(*self, ref mut inner => inner.nth_back(n))
|
||||
}
|
||||
|
||||
fn rfold<Acc, G>(self, init: Acc, f: G) -> Acc
|
||||
where
|
||||
G: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
for_both!(self, inner => inner.rfold(init, f))
|
||||
}
|
||||
|
||||
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where
|
||||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
for_both!(*self, ref mut inner => inner.rfind(predicate))
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> ExactSizeIterator for Either<L, R>
|
||||
where
|
||||
L: ExactSizeIterator,
|
||||
R: ExactSizeIterator<Item = L::Item>,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
for_both!(*self, ref inner => inner.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> iter::FusedIterator for Either<L, R>
|
||||
where
|
||||
L: iter::FusedIterator,
|
||||
R: iter::FusedIterator<Item = L::Item>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<L, R> Iterator for IterEither<L, R>
|
||||
where
|
||||
L: Iterator,
|
||||
R: Iterator,
|
||||
{
|
||||
type Item = Either<L::Item, R::Item>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
Some(map_either!(self.inner, ref mut inner => inner.next()?))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
for_both!(self.inner, ref inner => inner.size_hint())
|
||||
}
|
||||
|
||||
fn fold<Acc, G>(self, init: Acc, f: G) -> Acc
|
||||
where
|
||||
G: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
wrap_either!(self.inner => .fold(init, f))
|
||||
}
|
||||
|
||||
fn for_each<F>(self, f: F)
|
||||
where
|
||||
F: FnMut(Self::Item),
|
||||
{
|
||||
wrap_either!(self.inner => .for_each(f))
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
for_both!(self.inner, inner => inner.count())
|
||||
}
|
||||
|
||||
fn last(self) -> Option<Self::Item> {
|
||||
Some(map_either!(self.inner, inner => inner.last()?))
|
||||
}
|
||||
|
||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||
Some(map_either!(self.inner, ref mut inner => inner.nth(n)?))
|
||||
}
|
||||
|
||||
fn collect<B>(self) -> B
|
||||
where
|
||||
B: iter::FromIterator<Self::Item>,
|
||||
{
|
||||
wrap_either!(self.inner => .collect())
|
||||
}
|
||||
|
||||
fn partition<B, F>(self, f: F) -> (B, B)
|
||||
where
|
||||
B: Default + Extend<Self::Item>,
|
||||
F: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
wrap_either!(self.inner => .partition(f))
|
||||
}
|
||||
|
||||
fn all<F>(&mut self, f: F) -> bool
|
||||
where
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
wrap_either!(&mut self.inner => .all(f))
|
||||
}
|
||||
|
||||
fn any<F>(&mut self, f: F) -> bool
|
||||
where
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
wrap_either!(&mut self.inner => .any(f))
|
||||
}
|
||||
|
||||
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where
|
||||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
wrap_either!(&mut self.inner => .find(predicate))
|
||||
}
|
||||
|
||||
fn find_map<B, F>(&mut self, f: F) -> Option<B>
|
||||
where
|
||||
F: FnMut(Self::Item) -> Option<B>,
|
||||
{
|
||||
wrap_either!(&mut self.inner => .find_map(f))
|
||||
}
|
||||
|
||||
fn position<P>(&mut self, predicate: P) -> Option<usize>
|
||||
where
|
||||
P: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
wrap_either!(&mut self.inner => .position(predicate))
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> DoubleEndedIterator for IterEither<L, R>
|
||||
where
|
||||
L: DoubleEndedIterator,
|
||||
R: DoubleEndedIterator,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
Some(map_either!(self.inner, ref mut inner => inner.next_back()?))
|
||||
}
|
||||
|
||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
||||
Some(map_either!(self.inner, ref mut inner => inner.nth_back(n)?))
|
||||
}
|
||||
|
||||
fn rfold<Acc, G>(self, init: Acc, f: G) -> Acc
|
||||
where
|
||||
G: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
wrap_either!(self.inner => .rfold(init, f))
|
||||
}
|
||||
|
||||
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where
|
||||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
wrap_either!(&mut self.inner => .rfind(predicate))
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> ExactSizeIterator for IterEither<L, R>
|
||||
where
|
||||
L: ExactSizeIterator,
|
||||
R: ExactSizeIterator,
|
||||
{
|
||||
fn len(&self) -> usize {
|
||||
for_both!(self.inner, ref inner => inner.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, R> iter::FusedIterator for IterEither<L, R>
|
||||
where
|
||||
L: iter::FusedIterator,
|
||||
R: iter::FusedIterator,
|
||||
{
|
||||
}
|
1575
vendor/either/src/lib.rs
vendored
Normal file
1575
vendor/either/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
69
vendor/either/src/serde_untagged.rs
vendored
Normal file
69
vendor/either/src/serde_untagged.rs
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
//! Untagged serialization/deserialization support for Either<L, R>.
|
||||
//!
|
||||
//! `Either` uses default, externally-tagged representation.
|
||||
//! However, sometimes it is useful to support several alternative types.
|
||||
//! For example, we may have a field which is generally Map<String, i32>
|
||||
//! but in typical cases Vec<String> would suffice, too.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! use either::Either;
|
||||
//! use std::collections::HashMap;
|
||||
//!
|
||||
//! #[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||
//! #[serde(transparent)]
|
||||
//! struct IntOrString {
|
||||
//! #[serde(with = "either::serde_untagged")]
|
||||
//! inner: Either<Vec<String>, HashMap<String, i32>>
|
||||
//! };
|
||||
//!
|
||||
//! // serialization
|
||||
//! let data = IntOrString {
|
||||
//! inner: Either::Left(vec!["Hello".to_string()])
|
||||
//! };
|
||||
//! // notice: no tags are emitted.
|
||||
//! assert_eq!(serde_json::to_string(&data)?, r#"["Hello"]"#);
|
||||
//!
|
||||
//! // deserialization
|
||||
//! let data: IntOrString = serde_json::from_str(
|
||||
//! r#"{"a": 0, "b": 14}"#
|
||||
//! )?;
|
||||
//! println!("found {:?}", data);
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Either<L, R> {
|
||||
Left(L),
|
||||
Right(R),
|
||||
}
|
||||
|
||||
pub fn serialize<L, R, S>(this: &super::Either<L, R>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
L: Serialize,
|
||||
R: Serialize,
|
||||
{
|
||||
let untagged = match this {
|
||||
super::Either::Left(left) => Either::Left(left),
|
||||
super::Either::Right(right) => Either::Right(right),
|
||||
};
|
||||
untagged.serialize(serializer)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, L, R, D>(deserializer: D) -> Result<super::Either<L, R>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
L: Deserialize<'de>,
|
||||
R: Deserialize<'de>,
|
||||
{
|
||||
match Either::deserialize(deserializer) {
|
||||
Ok(Either::Left(left)) => Ok(super::Either::Left(left)),
|
||||
Ok(Either::Right(right)) => Ok(super::Either::Right(right)),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
74
vendor/either/src/serde_untagged_optional.rs
vendored
Normal file
74
vendor/either/src/serde_untagged_optional.rs
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
//! Untagged serialization/deserialization support for Option<Either<L, R>>.
|
||||
//!
|
||||
//! `Either` uses default, externally-tagged representation.
|
||||
//! However, sometimes it is useful to support several alternative types.
|
||||
//! For example, we may have a field which is generally Map<String, i32>
|
||||
//! but in typical cases Vec<String> would suffice, too.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! use either::Either;
|
||||
//! use std::collections::HashMap;
|
||||
//!
|
||||
//! #[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||
//! #[serde(transparent)]
|
||||
//! struct IntOrString {
|
||||
//! #[serde(with = "either::serde_untagged_optional")]
|
||||
//! inner: Option<Either<Vec<String>, HashMap<String, i32>>>
|
||||
//! };
|
||||
//!
|
||||
//! // serialization
|
||||
//! let data = IntOrString {
|
||||
//! inner: Some(Either::Left(vec!["Hello".to_string()]))
|
||||
//! };
|
||||
//! // notice: no tags are emitted.
|
||||
//! assert_eq!(serde_json::to_string(&data)?, r#"["Hello"]"#);
|
||||
//!
|
||||
//! // deserialization
|
||||
//! let data: IntOrString = serde_json::from_str(
|
||||
//! r#"{"a": 0, "b": 14}"#
|
||||
//! )?;
|
||||
//! println!("found {:?}", data);
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Either<L, R> {
|
||||
Left(L),
|
||||
Right(R),
|
||||
}
|
||||
|
||||
pub fn serialize<L, R, S>(
|
||||
this: &Option<super::Either<L, R>>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
L: Serialize,
|
||||
R: Serialize,
|
||||
{
|
||||
let untagged = match this {
|
||||
Some(super::Either::Left(left)) => Some(Either::Left(left)),
|
||||
Some(super::Either::Right(right)) => Some(Either::Right(right)),
|
||||
None => None,
|
||||
};
|
||||
untagged.serialize(serializer)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, L, R, D>(deserializer: D) -> Result<Option<super::Either<L, R>>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
L: Deserialize<'de>,
|
||||
R: Deserialize<'de>,
|
||||
{
|
||||
match Option::deserialize(deserializer) {
|
||||
Ok(Some(Either::Left(left))) => Ok(Some(super::Either::Left(left))),
|
||||
Ok(Some(Either::Right(right))) => Ok(Some(super::Either::Right(right))),
|
||||
Ok(None) => Ok(None),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
1
vendor/itertools/.cargo-checksum.json
vendored
Normal file
1
vendor/itertools/.cargo-checksum.json
vendored
Normal file
File diff suppressed because one or more lines are too long
319
vendor/itertools/CHANGELOG.md
vendored
Normal file
319
vendor/itertools/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,319 @@
|
||||
# Changelog
|
||||
|
||||
## 0.9.0
|
||||
- Fix potential overflow in `MergeJoinBy::size_hint` (#385)
|
||||
- Add `derive(Clone)` where possible (#382)
|
||||
- Add `try_collect` method (#394)
|
||||
- Add `HomogeneousTuple` trait (#389)
|
||||
- Fix `combinations(0)` and `combinations_with_replacement(0)` (#383)
|
||||
- Don't require `ParitalEq` to the `Item` of `DedupBy` (#397)
|
||||
- Implement missing specializations on the `PutBack` adaptor and on the `MergeJoinBy` iterator (#372)
|
||||
- Add `position_*` methods (#412)
|
||||
- Derive `Hash` for `EitherOrBoth` (#417)
|
||||
- Increase minimum supported Rust version to 1.32.0
|
||||
|
||||
## 0.8.2
|
||||
- Use `slice::iter` instead of `into_iter` to avoid future breakage (#378, by @LukasKalbertodt)
|
||||
## 0.8.1
|
||||
- Added a [`.exactly_one()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.exactly_one) iterator method that, on success, extracts the single value of an iterator ; by @Xaeroxe
|
||||
- Added combinatory iterator adaptors:
|
||||
- [`.permutations(k)`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.permutations):
|
||||
|
||||
`[0, 1, 2].iter().permutations(2)` yields
|
||||
|
||||
```rust
|
||||
[
|
||||
vec![0, 1],
|
||||
vec![0, 2],
|
||||
vec![1, 0],
|
||||
vec![1, 2],
|
||||
vec![2, 0],
|
||||
vec![2, 1],
|
||||
]
|
||||
```
|
||||
|
||||
; by @tobz1000
|
||||
|
||||
- [`.combinations_with_replacement(k)`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.combinations_with_replacement):
|
||||
|
||||
`[0, 1, 2].iter().combinations_with_replacement(2)` yields
|
||||
|
||||
```rust
|
||||
[
|
||||
vec![0, 0],
|
||||
vec![0, 1],
|
||||
vec![0, 2],
|
||||
vec![1, 1],
|
||||
vec![1, 2],
|
||||
vec![2, 2],
|
||||
]
|
||||
```
|
||||
|
||||
; by @tommilligan
|
||||
|
||||
- For reference, these methods join the already existing [`.combinations(k)`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.combinations):
|
||||
|
||||
`[0, 1, 2].iter().combinations(2)` yields
|
||||
|
||||
```rust
|
||||
[
|
||||
vec![0, 1],
|
||||
vec![0, 2],
|
||||
vec![1, 2],
|
||||
]
|
||||
```
|
||||
|
||||
- Improved the performance of [`.fold()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.fold)-based internal iteration for the [`.intersperse()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.intersperse) iterator ; by @jswrenn
|
||||
- Added [`.dedup_by()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.dedup_by), [`.merge_by()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.merge_by) and [`.kmerge_by()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.kmerge_by) adaptors that work like [`.dedup()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.dedup), [`.merge()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.merge) and [`.kmerge()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.kmerge), but taking an additional custom comparison closure parameter. ; by @phimuemue
|
||||
- Improved the performance of [`.all_equal()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.all_equal) ; by @fyrchik
|
||||
- Loosened the bounds on [`.partition_map()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.partition_map) to take just a `FnMut` closure rather than a `Fn` closure, and made its implementation use internal iteration for better performance ; by @danielhenrymantilla
|
||||
- Added convenience methods to [`EitherOrBoth`](https://docs.rs/itertools/0.8.1/itertools/enum.EitherOrBoth.html) elements yielded from the [`.zip_longest()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.zip_longest) iterator adaptor ; by @Avi-D-coder
|
||||
- Added [`.sum1()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.sum1) and [`.product1()`](https://docs.rs/itertools/0.8.1/itertools/trait.Itertools.html#method.product1) iterator methods that respectively try to return the sum and the product of the elements of an iterator **when it is not empty**, otherwise they return `None` ; by @Emerentius
|
||||
## 0.8.0
|
||||
- Added new adaptor `.map_into()` for conversions using `Into` by @vorner
|
||||
- Improved `Itertools` docs by @JohnHeitmann
|
||||
- The return type of `.sorted_by_by_key()` is now an iterator, not a Vec.
|
||||
- The return type of the `izip!(x, y)` macro with exactly two arguments is now the usual `Iterator::zip`.
|
||||
- Remove `.flatten()` in favour of std's `.flatten()`
|
||||
- Deprecate `.foreach()` in favour of std's `.for_each()`
|
||||
- Deprecate `.step()` in favour of std's `.step_by()`
|
||||
- Deprecate `repeat_call` in favour of std's `repeat_with`
|
||||
- Deprecate `.fold_while()` in favour of std's `.try_fold()`
|
||||
- Require Rust 1.24 as minimal version.
|
||||
## 0.7.11
|
||||
- Add convenience methods to `EitherOrBoth`, making it more similar to `Option` and `Either` by @jethrogb
|
||||
## 0.7.10
|
||||
- No changes.
|
||||
## 0.7.9
|
||||
- New inclusion policy: See the readme about suggesting features for std before accepting them in itertools.
|
||||
- The `FoldWhile` type now implements `Eq` and `PartialEq` by @jturner314
|
||||
## 0.7.8
|
||||
- Add new iterator method `.tree_fold1()` which is like `.fold1()` except items are combined in a tree structure (see its docs). By @scottmcm
|
||||
- Add more `Debug` impls by @phimuemue: KMerge, KMergeBy, MergeJoinBy, ConsTuples, Intersperse, ProcessResults, RcIter, Tee, TupleWindows, Tee, ZipLongest, ZipEq, Zip.
|
||||
## 0.7.7
|
||||
- Add new iterator method `.into_group_map() -> HashMap<K, Vec<V>>` which turns an iterator of `(K, V)` elements into such a hash table, where values are grouped by key. By @tobz1000
|
||||
- Add new free function `flatten` for the `.flatten()` adaptor. **NOTE:** recent Rust nightlies have `Iterator::flatten` and thus a clash with our flatten adaptor. One workaround is to use the itertools `flatten` free function.
|
||||
## 0.7.6
|
||||
- Add new adaptor `.multi_cartesian_product()` which is an n-ary product iterator by @tobz1000
|
||||
- Add new method `.sorted_by_key()` by @Xion
|
||||
- Provide simpler and faster `.count()` for `.unique()` and `.unique_by()`
|
||||
## 0.7.5
|
||||
- `.multipeek()` now implements `PeekingNext`, by @nicopap.
|
||||
## 0.7.4
|
||||
- Add new adaptor `.update()` by @lucasem; this adaptor is used to modify an element before passing it on in an iterator chain.
|
||||
## 0.7.3
|
||||
- Add new method `.collect_tuple()` by @matklad; it makes a tuple out of the iterator's elements if the number of them matches **exactly**.
|
||||
- Implement `fold` and `collect` for `.map_results()` which means it reuses the code of the standard `.map()` for these methods.
|
||||
## 0.7.2
|
||||
- Add new adaptor `.merge_join_by` by @srijs; a heterogeneous merge join for two ordered sequences.
|
||||
## 0.7.1
|
||||
- Iterator adaptors and iterators in itertools now use the same `must_use` reminder that the standard library adaptors do, by @matematikaedit and @bluss *“iterator adaptors are lazy and do nothing unless consumed”*.
|
||||
## 0.7.0
|
||||
- Faster `izip!()` by @krdln
|
||||
- `izip!()` is now a wrapper for repeated regular `.zip()` and a single `.map()`. This means it optimizes as well as the standard library `.zip()` it uses. **Note:** `multizip` and `izip!()` are now different! The former has a named type but the latter optimizes better.
|
||||
- Faster `.unique()`
|
||||
- `no_std` support, which is opt-in!
|
||||
- Many lovable features are still there without std, like `izip!()` or `.format()` or `.merge()`, but not those that use collections.
|
||||
- Trait bounds were required up front instead of just on the type: `group_by`'s `PartialEq` by @Phlosioneer and `repeat_call`'s `FnMut`.
|
||||
- Removed deprecated constructor `Zip::new` — use `izip!()` or `multizip()`
|
||||
## 0.6.5
|
||||
- Fix bug in `.cartesian_product()`'s fold (which only was visible for unfused iterators).
|
||||
## 0.6.4
|
||||
- Add specific `fold` implementations for `.cartesian_product()` and `cons_tuples()`, which improves their performance in fold, foreach, and iterator consumers derived from them.
|
||||
## 0.6.3
|
||||
- Add iterator adaptor `.positions(predicate)` by @tmccombs
|
||||
## 0.6.2
|
||||
- Add function `process_results` which can “lift” a function of the regular values of an iterator so that it can process the `Ok` values from an iterator of `Results` instead, by @shepmaster
|
||||
- Add iterator method `.concat()` which combines all iterator elements into a single collection using the `Extend` trait, by @srijs
|
||||
## 0.6.1
|
||||
- Better size hint testing and subsequent size hint bugfixes by @rkarp. Fixes bugs in product, `interleave_shortest` size hints.
|
||||
- New iterator method `.all_equal()` by @phimuemue
|
||||
## 0.6.0
|
||||
- Deprecated names were removed in favour of their replacements
|
||||
- `.flatten()` does not implement double ended iteration anymore
|
||||
- `.fold_while()` uses `&mut self` and returns `FoldWhile<T>`, for composability #168
|
||||
- `.foreach()` and `.fold1()` use `self`, like `.fold()` does.
|
||||
- `.combinations(0)` now produces a single empty vector. #174
|
||||
## 0.5.10
|
||||
- Add itertools method `.kmerge_by()` (and corresponding free function)
|
||||
- Relaxed trait requirement of `.kmerge()` and `.minmax()` to PartialOrd.
|
||||
## 0.5.9
|
||||
- Add multipeek method `.reset_peek()`
|
||||
- Add categories
|
||||
## 0.5.8
|
||||
- Add iterator adaptor `.peeking_take_while()` and its trait `PeekingNext`.
|
||||
## 0.5.7
|
||||
- Add iterator adaptor `.with_position()`
|
||||
- Fix multipeek's performance for long peeks by using `VecDeque`.
|
||||
## 0.5.6
|
||||
- Add `.map_results()`
|
||||
## 0.5.5
|
||||
- Many more adaptors now implement `Debug`
|
||||
- Add free function constructor `repeat_n`. `RepeatN::new` is now deprecated.
|
||||
## 0.5.4
|
||||
- Add infinite generator function `iterate`, that takes a seed and a closure.
|
||||
## 0.5.3
|
||||
- Special-cased `.fold()` for flatten and put back. `.foreach()` now uses fold on the iterator, to pick up any iterator specific loop implementation.
|
||||
- `.combinations(n)` asserts up front that `n != 0`, instead of running into an error on the second iterator element.
|
||||
## 0.5.2
|
||||
- Add `.tuples::<T>()` that iterates by two, three or four elements at a time (where `T` is a tuple type).
|
||||
- Add `.tuple_windows::<T>()` that iterates using a window of the two, three or four most recent elements.
|
||||
- Add `.next_tuple::<T>()` method, that picks the next two, three or four elements in one go.
|
||||
- `.interleave()` now has an accurate size hint.
|
||||
## 0.5.1
|
||||
- Workaround module/function name clash that made racer crash on completing itertools. Only internal changes needed.
|
||||
## 0.5.0
|
||||
- [Release announcement](http://bluss.github.io/rust/2016/09/26/itertools-0.5.0/)
|
||||
- Renamed:
|
||||
- `combinations` is now `tuple_combinations`
|
||||
- `combinations_n` to `combinations`
|
||||
- `group_by_lazy`, `chunks_lazy` to `group_by`, `chunks`
|
||||
- `Unfold::new` to `unfold()`
|
||||
- `RepeatCall::new` to `repeat_call()`
|
||||
- `Zip::new` to `multizip`
|
||||
- `PutBack::new`, `PutBackN::new` to `put_back`, `put_back_n`
|
||||
- `PutBack::with_value` is now a builder setter, not a constructor
|
||||
- `MultiPeek::new`, `.multipeek()` to `multipeek()`
|
||||
- `format` to `format_with` and `format_default` to `format`
|
||||
- `.into_rc()` to `rciter`
|
||||
- `Partition` enum is now `Either`
|
||||
- Module reorganization:
|
||||
- All iterator structs are under `itertools::structs` but also reexported to the top level, for backwards compatibility
|
||||
- All free functions are reexported at the root, `itertools::free` will be removed in the next version
|
||||
- Removed:
|
||||
- `ZipSlices`, use `.zip()` instead
|
||||
- `.enumerate_from()`, `ZipTrusted`, due to being unstable
|
||||
- `.mend_slices()`, moved to crate `odds`
|
||||
- Stride, StrideMut, moved to crate `odds`
|
||||
- `linspace()`, moved to crate `itertools-num`
|
||||
- `.sort_by()`, use `.sorted_by()`
|
||||
- `.is_empty_hint()`, use `.size_hint()`
|
||||
- `.dropn()`, use `.dropping()`
|
||||
- `.map_fn()`, use `.map()`
|
||||
- `.slice()`, use `.take()` / `.skip()`
|
||||
- helper traits in `misc`
|
||||
- `new` constructors on iterator structs, use `Itertools` trait or free functions instead
|
||||
- `itertools::size_hint` is now private
|
||||
- Behaviour changes:
|
||||
- `format` and `format_with` helpers now panic if you try to format them more than once.
|
||||
- `repeat_call` is not double ended anymore
|
||||
- New features:
|
||||
- tuple flattening iterator is constructible with `cons_tuples`
|
||||
- itertools reexports `Either` from the `either` crate. `Either<L, R>` is an iterator when `L, R` are.
|
||||
- `MinMaxResult` now implements `Copy` and `Clone`
|
||||
- `tuple_combinations` supports 1-4 tuples of combinations (previously just 2)
|
||||
## 0.4.19
|
||||
- Add `.minmax_by()`
|
||||
- Add `itertools::free::cloned`
|
||||
- Add `itertools::free::rciter`
|
||||
- Improve `.step(n)` slightly to take advantage of specialized Fuse better.
|
||||
## 0.4.18
|
||||
- Only changes related to the "unstable" crate feature. This feature is more or less deprecated.
|
||||
- Use deprecated warnings when unstable is enabled. `.enumerate_from()` will be removed imminently since it's using a deprecated libstd trait.
|
||||
## 0.4.17
|
||||
- Fix bug in `.kmerge()` that caused it to often produce the wrong order #134
|
||||
## 0.4.16
|
||||
- Improve precision of the `interleave_shortest` adaptor's size hint (it is now computed exactly when possible).
|
||||
## 0.4.15
|
||||
- Fixup on top of the workaround in 0.4.14. A function in `itertools::free` was removed by mistake and now it is added back again.
|
||||
## 0.4.14
|
||||
- Workaround an upstream regression in a rust nightly build that broke compilation of of `itertools::free::{interleave, merge}`
|
||||
## 0.4.13
|
||||
- Add `.minmax()` and `.minmax_by_key()`, iterator methods for finding both minimum and maximum in one scan.
|
||||
- Add `.format_default()`, a simpler version of `.format()` (lazy formatting for iterators).
|
||||
## 0.4.12
|
||||
- Add `.zip_eq()`, an adaptor like `.zip()` except it ensures iterators of inequal length don't pass silently (instead it panics).
|
||||
- Add `.fold_while()`, an iterator method that is a fold that can short-circuit.
|
||||
- Add `.partition_map()`, an iterator method that can separate elements into two collections.
|
||||
## 0.4.11
|
||||
- Add `.get()` for `Stride{,Mut}` and `.get_mut()` for `StrideMut`
|
||||
## 0.4.10
|
||||
- Improve performance of `.kmerge()`
|
||||
## 0.4.9
|
||||
- Add k-ary merge adaptor `.kmerge()`
|
||||
- Fix a bug in `.islice()` with ranges `a..b` where a `> b`.
|
||||
## 0.4.8
|
||||
- Implement `Clone`, `Debug` for `Linspace`
|
||||
## 0.4.7
|
||||
- Add function `diff_with()` that compares two iterators
|
||||
- Add `.combinations_n()`, an n-ary combinations iterator
|
||||
- Add methods `PutBack::with_value` and `PutBack::into_parts`.
|
||||
## 0.4.6
|
||||
- Add method `.sorted()`
|
||||
- Add module `itertools::free` with free function variants of common iterator adaptors and methods. For example `enumerate(iterable)`, `rev(iterable)`, and so on.
|
||||
## 0.4.5
|
||||
- Add `.flatten()`
|
||||
## 0.4.4
|
||||
- Allow composing `ZipSlices` with itself
|
||||
## 0.4.3
|
||||
- Write `iproduct!()` as a single expression; this allows temporary values in its arguments.
|
||||
## 0.4.2
|
||||
- Add `.fold_options()`
|
||||
- Require Rust 1.1 or later
|
||||
## 0.4.1
|
||||
- Update `.dropping()` to take advantage of `.nth()`
|
||||
## 0.4.0
|
||||
- `.merge()`, `.unique()` and `.dedup()` now perform better due to not using function pointers
|
||||
- Add free functions `enumerate()` and `rev()`
|
||||
- Breaking changes:
|
||||
- Return types of `.merge()` and `.merge_by()` renamed and changed
|
||||
- Method `Merge::new` removed
|
||||
- `.merge_by()` now takes a closure that returns bool.
|
||||
- Return type of `.dedup()` changed
|
||||
- Return type of `.mend_slices()` changed
|
||||
- Return type of `.unique()` changed
|
||||
- Removed function `times()`, struct `Times`: use a range instead
|
||||
- Removed deprecated macro `icompr!()`
|
||||
- Removed deprecated `FnMap` and method `.fn_map()`: use `.map_fn()`
|
||||
- `.interleave_shortest()` is no longer guaranteed to act like fused
|
||||
## 0.3.25
|
||||
- Rename `.sort_by()` to `.sorted_by()`. Old name is deprecated.
|
||||
- Fix well-formedness warnings from RFC 1214, no user visible impact
|
||||
## 0.3.24
|
||||
- Improve performance of `.merge()`'s ordering function slightly
|
||||
## 0.3.23
|
||||
- Added `.chunks()`, similar to (and based on) `.group_by_lazy()`.
|
||||
- Tweak linspace to match numpy.linspace and make it double ended.
|
||||
## 0.3.22
|
||||
- Added `ZipSlices`, a fast zip for slices
|
||||
## 0.3.21
|
||||
- Remove `Debug` impl for `Format`, it will have different use later
|
||||
## 0.3.20
|
||||
- Optimize `.group_by_lazy()`
|
||||
## 0.3.19
|
||||
- Added `.group_by_lazy()`, a possibly nonallocating group by
|
||||
- Added `.format()`, a nonallocating formatting helper for iterators
|
||||
- Remove uses of `RandomAccessIterator` since it has been deprecated in rust.
|
||||
## 0.3.17
|
||||
- Added (adopted) `Unfold` from rust
|
||||
## 0.3.16
|
||||
- Added adaptors `.unique()`, `.unique_by()`
|
||||
## 0.3.15
|
||||
- Added method `.sort_by()`
|
||||
## 0.3.14
|
||||
- Added adaptor `.while_some()`
|
||||
## 0.3.13
|
||||
- Added adaptor `.interleave_shortest()`
|
||||
- Added adaptor `.pad_using()`
|
||||
## 0.3.11
|
||||
- Added `assert_equal` function
|
||||
## 0.3.10
|
||||
- Bugfix `.combinations()` `size_hint`.
|
||||
## 0.3.8
|
||||
- Added source `RepeatCall`
|
||||
## 0.3.7
|
||||
- Added adaptor `PutBackN`
|
||||
- Added adaptor `.combinations()`
|
||||
## 0.3.6
|
||||
- Added `itertools::partition`, partition a sequence in place based on a predicate.
|
||||
- Deprecate `icompr!()` with no replacement.
|
||||
## 0.3.5
|
||||
- `.map_fn()` replaces deprecated `.fn_map()`.
|
||||
## 0.3.4
|
||||
- `.take_while_ref()` *by-ref adaptor*
|
||||
- `.coalesce()` *adaptor*
|
||||
- `.mend_slices()` *adaptor*
|
||||
## 0.3.3
|
||||
- `.dropping_back()` *method*
|
||||
- `.fold1()` *method*
|
||||
- `.is_empty_hint()` *method*
|
584
vendor/itertools/Cargo.lock
generated
vendored
Normal file
584
vendor/itertools/Cargo.lock
generated
vendored
Normal file
@ -0,0 +1,584 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "c2-chacha"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"criterion-plot 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tinytemplate 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bstr 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "permutohedron"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quickcheck"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_os"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xoshiro"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum bstr 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "502ae1441a0a5adb8fbd38a5955a6416b9493e92b465de5e4a9bde6a539c2c48"
|
||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
|
||||
"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6"
|
||||
"checksum criterion-plot 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a01e15e0ea58e8234f96146b1f91fa9d0e4dd7a38da93ff7a75d42c0b9d3a545"
|
||||
"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
|
||||
"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
|
||||
"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
|
||||
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
|
||||
"checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279"
|
||||
"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c"
|
||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
|
||||
"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||
"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223"
|
||||
"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
|
||||
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||
"checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c"
|
||||
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||
"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
|
||||
"checksum quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
|
||||
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a"
|
||||
"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff"
|
||||
"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
|
||||
"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
|
||||
"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
||||
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
||||
"checksum serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "15913895b61e0be854afd32fd4163fcd2a3df34142cf2cb961b310ce694cbf90"
|
||||
"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum tinytemplate 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "57a3c6667d3e65eb1bc3aed6fd14011c6cbc3a0665218ab7f5daf040b9ec371a"
|
||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
75
vendor/itertools/Cargo.toml
vendored
Normal file
75
vendor/itertools/Cargo.toml
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
authors = ["bluss"]
|
||||
exclude = ["/bors.toml"]
|
||||
description = "Extra iterator adaptors, iterator methods, free functions, and macros."
|
||||
documentation = "https://docs.rs/itertools/"
|
||||
keywords = ["iterator", "data-structure", "zip", "product", "group-by"]
|
||||
categories = ["algorithms", "rust-patterns"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/bluss/rust-itertools"
|
||||
[package.metadata.release]
|
||||
no-dev-version = true
|
||||
[profile.bench]
|
||||
debug = true
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
bench = false
|
||||
|
||||
[[bench]]
|
||||
name = "tuple_combinations"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "tuples"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "fold_specialization"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "combinations_with_replacement"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "tree_fold1"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "bench1"
|
||||
harness = false
|
||||
[dependencies.either]
|
||||
version = "1.0"
|
||||
default-features = false
|
||||
[dev-dependencies.criterion]
|
||||
version = "=0.3.0"
|
||||
|
||||
[dev-dependencies.permutohedron]
|
||||
version = "0.2"
|
||||
|
||||
[dev-dependencies.quickcheck]
|
||||
version = "0.9"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.7"
|
||||
|
||||
[features]
|
||||
default = ["use_std"]
|
||||
use_std = []
|
201
vendor/itertools/LICENSE-APACHE
vendored
Normal file
201
vendor/itertools/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
25
vendor/itertools/LICENSE-MIT
vendored
Normal file
25
vendor/itertools/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
Copyright (c) 2015
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
55
vendor/itertools/README.rst
vendored
Normal file
55
vendor/itertools/README.rst
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
|
||||
Itertools
|
||||
=========
|
||||
|
||||
Extra iterator adaptors, functions and macros.
|
||||
|
||||
Please read the `API documentation here`__
|
||||
|
||||
__ https://docs.rs/itertools/
|
||||
|
||||
|build_status|_ |crates|_
|
||||
|
||||
.. |build_status| image:: https://travis-ci.org/rust-itertools/itertools.svg?branch=master
|
||||
.. _build_status: https://travis-ci.org/rust-itertools/itertools
|
||||
|
||||
.. |crates| image:: http://meritbadge.herokuapp.com/itertools
|
||||
.. _crates: https://crates.io/crates/itertools
|
||||
|
||||
How to use with cargo:
|
||||
|
||||
.. code:: toml
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.8"
|
||||
|
||||
How to use in your crate:
|
||||
|
||||
.. code:: rust
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
How to contribute
|
||||
-----------------
|
||||
|
||||
- Fix a bug or implement a new thing
|
||||
- Include tests for your new feature, preferably a quickcheck test
|
||||
- Make a Pull Request
|
||||
|
||||
For new features, please first consider filing a PR to `rust-lang/rust <https://github.com/rust-lang/rust/>`_,
|
||||
adding your new feature to the `Iterator` trait of the standard library, if you believe it is reasonable.
|
||||
If it isn't accepted there, proposing it for inclusion in ``itertools`` is a good idea.
|
||||
The reason for doing is this is so that we avoid future breakage as with ``.flatten()``.
|
||||
However, if your feature involves heap allocation, such as storing elements in a ``Vec<T>``,
|
||||
then it can't be accepted into ``libcore``, and you should propose it for ``itertools`` directly instead.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Dual-licensed to be compatible with the Rust project.
|
||||
|
||||
Licensed under the Apache License, Version 2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
|
||||
http://opensource.org/licenses/MIT, at your
|
||||
option. This file may not be copied, modified, or distributed
|
||||
except according to those terms.
|
877
vendor/itertools/benches/bench1.rs
vendored
Normal file
877
vendor/itertools/benches/bench1.rs
vendored
Normal file
@ -0,0 +1,877 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use itertools::Itertools;
|
||||
use itertools::free::cloned;
|
||||
use itertools::iproduct;
|
||||
|
||||
use std::iter::repeat;
|
||||
use std::cmp;
|
||||
use std::ops::{Add, Range};
|
||||
|
||||
mod extra;
|
||||
|
||||
use crate::extra::ZipSlices;
|
||||
|
||||
fn slice_iter(c: &mut Criterion) {
|
||||
let xs: Vec<_> = repeat(1i32).take(20).collect();
|
||||
|
||||
c.bench_function("slice iter", move |b| {
|
||||
b.iter(|| for elt in xs.iter() {
|
||||
black_box(elt);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn slice_iter_rev(c: &mut Criterion) {
|
||||
let xs: Vec<_> = repeat(1i32).take(20).collect();
|
||||
|
||||
c.bench_function("slice iter rev", move |b| {
|
||||
b.iter(|| for elt in xs.iter().rev() {
|
||||
black_box(elt);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zip_default_zip(c: &mut Criterion) {
|
||||
let xs = vec![0; 1024];
|
||||
let ys = vec![0; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zip default zip", move |b| {
|
||||
b.iter(|| {
|
||||
for (&x, &y) in xs.iter().zip(&ys) {
|
||||
black_box(x);
|
||||
black_box(y);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipdot_i32_default_zip(c: &mut Criterion) {
|
||||
let xs = vec![2; 1024];
|
||||
let ys = vec![2; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipdot i32 default zip", move |b| {
|
||||
b.iter(|| {
|
||||
let mut s = 0;
|
||||
for (&x, &y) in xs.iter().zip(&ys) {
|
||||
s += x * y;
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipdot_f32_default_zip(c: &mut Criterion) {
|
||||
let xs = vec![2f32; 1024];
|
||||
let ys = vec![2f32; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipdot f32 default zip", move |b| {
|
||||
b.iter(|| {
|
||||
let mut s = 0.;
|
||||
for (&x, &y) in xs.iter().zip(&ys) {
|
||||
s += x * y;
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zip_default_zip3(c: &mut Criterion) {
|
||||
let xs = vec![0; 1024];
|
||||
let ys = vec![0; 768];
|
||||
let zs = vec![0; 766];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
let zs = black_box(zs);
|
||||
|
||||
c.bench_function("zip default zip3", move |b| {
|
||||
b.iter(|| {
|
||||
for ((&x, &y), &z) in xs.iter().zip(&ys).zip(&zs) {
|
||||
black_box(x);
|
||||
black_box(y);
|
||||
black_box(z);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zip_slices_ziptuple(c: &mut Criterion) {
|
||||
let xs = vec![0; 1024];
|
||||
let ys = vec![0; 768];
|
||||
|
||||
c.bench_function("zip slices ziptuple", move |b| {
|
||||
b.iter(|| {
|
||||
let xs = black_box(&xs);
|
||||
let ys = black_box(&ys);
|
||||
for (&x, &y) in itertools::multizip((xs, ys)) {
|
||||
black_box(x);
|
||||
black_box(y);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipslices(c: &mut Criterion) {
|
||||
let xs = vec![0; 1024];
|
||||
let ys = vec![0; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipslices", move |b| {
|
||||
b.iter(|| {
|
||||
for (&x, &y) in ZipSlices::new(&xs, &ys) {
|
||||
black_box(x);
|
||||
black_box(y);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipslices_mut(c: &mut Criterion) {
|
||||
let xs = vec![0; 1024];
|
||||
let ys = vec![0; 768];
|
||||
let xs = black_box(xs);
|
||||
let mut ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipslices mut", move |b| {
|
||||
b.iter(|| {
|
||||
for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
|
||||
black_box(x);
|
||||
black_box(y);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipdot_i32_zipslices(c: &mut Criterion) {
|
||||
let xs = vec![2; 1024];
|
||||
let ys = vec![2; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipdot i32 zipslices", move |b| {
|
||||
b.iter(|| {
|
||||
let mut s = 0i32;
|
||||
for (&x, &y) in ZipSlices::new(&xs, &ys) {
|
||||
s += x * y;
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipdot_f32_zipslices(c: &mut Criterion) {
|
||||
let xs = vec![2f32; 1024];
|
||||
let ys = vec![2f32; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipdot f32 zipslices", move |b| {
|
||||
b.iter(|| {
|
||||
let mut s = 0.;
|
||||
for (&x, &y) in ZipSlices::new(&xs, &ys) {
|
||||
s += x * y;
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zip_checked_counted_loop(c: &mut Criterion) {
|
||||
let xs = vec![0; 1024];
|
||||
let ys = vec![0; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zip checked counted loop", move |b| {
|
||||
b.iter(|| {
|
||||
// Must slice to equal lengths, and then bounds checks are eliminated!
|
||||
let len = cmp::min(xs.len(), ys.len());
|
||||
let xs = &xs[..len];
|
||||
let ys = &ys[..len];
|
||||
|
||||
for i in 0..len {
|
||||
let x = xs[i];
|
||||
let y = ys[i];
|
||||
black_box(x);
|
||||
black_box(y);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipdot_i32_checked_counted_loop(c: &mut Criterion) {
|
||||
let xs = vec![2; 1024];
|
||||
let ys = vec![2; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipdot i32 checked counted loop", move |b| {
|
||||
b.iter(|| {
|
||||
// Must slice to equal lengths, and then bounds checks are eliminated!
|
||||
let len = cmp::min(xs.len(), ys.len());
|
||||
let xs = &xs[..len];
|
||||
let ys = &ys[..len];
|
||||
|
||||
let mut s = 0i32;
|
||||
|
||||
for i in 0..len {
|
||||
s += xs[i] * ys[i];
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipdot_f32_checked_counted_loop(c: &mut Criterion) {
|
||||
let xs = vec![2f32; 1024];
|
||||
let ys = vec![2f32; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipdot f32 checked counted loop", move |b| {
|
||||
b.iter(|| {
|
||||
// Must slice to equal lengths, and then bounds checks are eliminated!
|
||||
let len = cmp::min(xs.len(), ys.len());
|
||||
let xs = &xs[..len];
|
||||
let ys = &ys[..len];
|
||||
|
||||
let mut s = 0.;
|
||||
|
||||
for i in 0..len {
|
||||
s += xs[i] * ys[i];
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipdot_f32_checked_counted_unrolled_loop(c: &mut Criterion) {
|
||||
let xs = vec![2f32; 1024];
|
||||
let ys = vec![2f32; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipdot f32 checked counted unrolled loop", move |b| {
|
||||
b.iter(|| {
|
||||
// Must slice to equal lengths, and then bounds checks are eliminated!
|
||||
let len = cmp::min(xs.len(), ys.len());
|
||||
let mut xs = &xs[..len];
|
||||
let mut ys = &ys[..len];
|
||||
|
||||
let mut s = 0.;
|
||||
let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) =
|
||||
(0., 0., 0., 0., 0., 0., 0., 0.);
|
||||
|
||||
// how to unroll and have bounds checks eliminated (by cristicbz)
|
||||
// split sum into eight parts to enable vectorization (by bluss)
|
||||
while xs.len() >= 8 {
|
||||
p0 += xs[0] * ys[0];
|
||||
p1 += xs[1] * ys[1];
|
||||
p2 += xs[2] * ys[2];
|
||||
p3 += xs[3] * ys[3];
|
||||
p4 += xs[4] * ys[4];
|
||||
p5 += xs[5] * ys[5];
|
||||
p6 += xs[6] * ys[6];
|
||||
p7 += xs[7] * ys[7];
|
||||
|
||||
xs = &xs[8..];
|
||||
ys = &ys[8..];
|
||||
}
|
||||
s += p0 + p4;
|
||||
s += p1 + p5;
|
||||
s += p2 + p6;
|
||||
s += p3 + p7;
|
||||
|
||||
for i in 0..xs.len() {
|
||||
s += xs[i] * ys[i];
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zip_unchecked_counted_loop(c: &mut Criterion) {
|
||||
let xs = vec![0; 1024];
|
||||
let ys = vec![0; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zip unchecked counted loop", move |b| {
|
||||
b.iter(|| {
|
||||
let len = cmp::min(xs.len(), ys.len());
|
||||
for i in 0..len {
|
||||
unsafe {
|
||||
let x = *xs.get_unchecked(i);
|
||||
let y = *ys.get_unchecked(i);
|
||||
black_box(x);
|
||||
black_box(y);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipdot_i32_unchecked_counted_loop(c: &mut Criterion) {
|
||||
let xs = vec![2; 1024];
|
||||
let ys = vec![2; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipdot i32 unchecked counted loop", move |b| {
|
||||
b.iter(|| {
|
||||
let len = cmp::min(xs.len(), ys.len());
|
||||
let mut s = 0i32;
|
||||
for i in 0..len {
|
||||
unsafe {
|
||||
let x = *xs.get_unchecked(i);
|
||||
let y = *ys.get_unchecked(i);
|
||||
s += x * y;
|
||||
}
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zipdot_f32_unchecked_counted_loop(c: &mut Criterion) {
|
||||
let xs = vec![2.; 1024];
|
||||
let ys = vec![2.; 768];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
|
||||
c.bench_function("zipdot f32 unchecked counted loop", move |b| {
|
||||
b.iter(|| {
|
||||
let len = cmp::min(xs.len(), ys.len());
|
||||
let mut s = 0f32;
|
||||
for i in 0..len {
|
||||
unsafe {
|
||||
let x = *xs.get_unchecked(i);
|
||||
let y = *ys.get_unchecked(i);
|
||||
s += x * y;
|
||||
}
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn zip_unchecked_counted_loop3(c: &mut Criterion) {
|
||||
let xs = vec![0; 1024];
|
||||
let ys = vec![0; 768];
|
||||
let zs = vec![0; 766];
|
||||
let xs = black_box(xs);
|
||||
let ys = black_box(ys);
|
||||
let zs = black_box(zs);
|
||||
|
||||
c.bench_function("zip unchecked counted loop3", move |b| {
|
||||
b.iter(|| {
|
||||
let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len()));
|
||||
for i in 0..len {
|
||||
unsafe {
|
||||
let x = *xs.get_unchecked(i);
|
||||
let y = *ys.get_unchecked(i);
|
||||
let z = *zs.get_unchecked(i);
|
||||
black_box(x);
|
||||
black_box(y);
|
||||
black_box(z);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn group_by_lazy_1(c: &mut Criterion) {
|
||||
let mut data = vec![0; 1024];
|
||||
for (index, elt) in data.iter_mut().enumerate() {
|
||||
*elt = index / 10;
|
||||
}
|
||||
|
||||
let data = black_box(data);
|
||||
|
||||
c.bench_function("group by lazy 1", move |b| {
|
||||
b.iter(|| {
|
||||
for (_key, group) in &data.iter().group_by(|elt| **elt) {
|
||||
for elt in group {
|
||||
black_box(elt);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn group_by_lazy_2(c: &mut Criterion) {
|
||||
let mut data = vec![0; 1024];
|
||||
for (index, elt) in data.iter_mut().enumerate() {
|
||||
*elt = index / 2;
|
||||
}
|
||||
|
||||
let data = black_box(data);
|
||||
|
||||
c.bench_function("group by lazy 2", move |b| {
|
||||
b.iter(|| {
|
||||
for (_key, group) in &data.iter().group_by(|elt| **elt) {
|
||||
for elt in group {
|
||||
black_box(elt);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn slice_chunks(c: &mut Criterion) {
|
||||
let data = vec![0; 1024];
|
||||
|
||||
let data = black_box(data);
|
||||
let sz = black_box(10);
|
||||
|
||||
c.bench_function("slice chunks", move |b| {
|
||||
b.iter(|| {
|
||||
for group in data.chunks(sz) {
|
||||
for elt in group {
|
||||
black_box(elt);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn chunks_lazy_1(c: &mut Criterion) {
|
||||
let data = vec![0; 1024];
|
||||
|
||||
let data = black_box(data);
|
||||
let sz = black_box(10);
|
||||
|
||||
c.bench_function("chunks lazy 1", move |b| {
|
||||
b.iter(|| {
|
||||
for group in &data.iter().chunks(sz) {
|
||||
for elt in group {
|
||||
black_box(elt);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn equal(c: &mut Criterion) {
|
||||
let data = vec![7; 1024];
|
||||
let l = data.len();
|
||||
let alpha = black_box(&data[1..]);
|
||||
let beta = black_box(&data[..l - 1]);
|
||||
|
||||
c.bench_function("equal", move |b| {
|
||||
b.iter(|| {
|
||||
itertools::equal(alpha, beta)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn merge_default(c: &mut Criterion) {
|
||||
let mut data1 = vec![0; 1024];
|
||||
let mut data2 = vec![0; 800];
|
||||
let mut x = 0;
|
||||
for (_, elt) in data1.iter_mut().enumerate() {
|
||||
*elt = x;
|
||||
x += 1;
|
||||
}
|
||||
|
||||
let mut y = 0;
|
||||
for (i, elt) in data2.iter_mut().enumerate() {
|
||||
*elt += y;
|
||||
if i % 3 == 0 {
|
||||
y += 3;
|
||||
} else {
|
||||
y += 0;
|
||||
}
|
||||
}
|
||||
let data1 = black_box(data1);
|
||||
let data2 = black_box(data2);
|
||||
|
||||
c.bench_function("merge default", move |b| {
|
||||
b.iter(|| {
|
||||
data1.iter().merge(&data2).count()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn merge_by_cmp(c: &mut Criterion) {
|
||||
let mut data1 = vec![0; 1024];
|
||||
let mut data2 = vec![0; 800];
|
||||
let mut x = 0;
|
||||
for (_, elt) in data1.iter_mut().enumerate() {
|
||||
*elt = x;
|
||||
x += 1;
|
||||
}
|
||||
|
||||
let mut y = 0;
|
||||
for (i, elt) in data2.iter_mut().enumerate() {
|
||||
*elt += y;
|
||||
if i % 3 == 0 {
|
||||
y += 3;
|
||||
} else {
|
||||
y += 0;
|
||||
}
|
||||
}
|
||||
let data1 = black_box(data1);
|
||||
let data2 = black_box(data2);
|
||||
|
||||
c.bench_function("merge by cmp", move |b| {
|
||||
b.iter(|| {
|
||||
data1.iter().merge_by(&data2, PartialOrd::le).count()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn merge_by_lt(c: &mut Criterion) {
|
||||
let mut data1 = vec![0; 1024];
|
||||
let mut data2 = vec![0; 800];
|
||||
let mut x = 0;
|
||||
for (_, elt) in data1.iter_mut().enumerate() {
|
||||
*elt = x;
|
||||
x += 1;
|
||||
}
|
||||
|
||||
let mut y = 0;
|
||||
for (i, elt) in data2.iter_mut().enumerate() {
|
||||
*elt += y;
|
||||
if i % 3 == 0 {
|
||||
y += 3;
|
||||
} else {
|
||||
y += 0;
|
||||
}
|
||||
}
|
||||
let data1 = black_box(data1);
|
||||
let data2 = black_box(data2);
|
||||
|
||||
c.bench_function("merge by lt", move |b| {
|
||||
b.iter(|| {
|
||||
data1.iter().merge_by(&data2, |a, b| a <= b).count()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn kmerge_default(c: &mut Criterion) {
|
||||
let mut data1 = vec![0; 1024];
|
||||
let mut data2 = vec![0; 800];
|
||||
let mut x = 0;
|
||||
for (_, elt) in data1.iter_mut().enumerate() {
|
||||
*elt = x;
|
||||
x += 1;
|
||||
}
|
||||
|
||||
let mut y = 0;
|
||||
for (i, elt) in data2.iter_mut().enumerate() {
|
||||
*elt += y;
|
||||
if i % 3 == 0 {
|
||||
y += 3;
|
||||
} else {
|
||||
y += 0;
|
||||
}
|
||||
}
|
||||
let data1 = black_box(data1);
|
||||
let data2 = black_box(data2);
|
||||
let its = &[data1.iter(), data2.iter()];
|
||||
|
||||
c.bench_function("kmerge default", move |b| {
|
||||
b.iter(|| {
|
||||
its.iter().cloned().kmerge().count()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn kmerge_tenway(c: &mut Criterion) {
|
||||
let mut data = vec![0; 10240];
|
||||
|
||||
let mut state = 1729u16;
|
||||
fn rng(state: &mut u16) -> u16 {
|
||||
let new = state.wrapping_mul(31421) + 6927;
|
||||
*state = new;
|
||||
new
|
||||
}
|
||||
|
||||
for elt in &mut data {
|
||||
*elt = rng(&mut state);
|
||||
}
|
||||
|
||||
let mut chunks = Vec::new();
|
||||
let mut rest = &mut data[..];
|
||||
while rest.len() > 0 {
|
||||
let chunk_len = 1 + rng(&mut state) % 512;
|
||||
let chunk_len = cmp::min(rest.len(), chunk_len as usize);
|
||||
let (fst, tail) = {rest}.split_at_mut(chunk_len);
|
||||
fst.sort();
|
||||
chunks.push(fst.iter().cloned());
|
||||
rest = tail;
|
||||
}
|
||||
|
||||
// println!("Chunk lengths: {}", chunks.iter().format_with(", ", |elt, f| f(&elt.len())));
|
||||
|
||||
c.bench_function("kmerge tenway", move |b| {
|
||||
b.iter(|| {
|
||||
chunks.iter().cloned().kmerge().count()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn fast_integer_sum<I>(iter: I) -> I::Item
|
||||
where I: IntoIterator,
|
||||
I::Item: Default + Add<Output=I::Item>
|
||||
{
|
||||
iter.into_iter().fold(<_>::default(), |x, y| x + y)
|
||||
}
|
||||
|
||||
fn step_vec_2(c: &mut Criterion) {
|
||||
let v = vec![0; 1024];
|
||||
|
||||
c.bench_function("step vec 2", move |b| {
|
||||
b.iter(|| {
|
||||
fast_integer_sum(cloned(v.iter().step_by(2)))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn step_vec_10(c: &mut Criterion) {
|
||||
let v = vec![0; 1024];
|
||||
|
||||
c.bench_function("step vec 10", move |b| {
|
||||
b.iter(|| {
|
||||
fast_integer_sum(cloned(v.iter().step_by(10)))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn step_range_2(c: &mut Criterion) {
|
||||
let v = black_box(0..1024);
|
||||
|
||||
c.bench_function("step range 2", move |b| {
|
||||
b.iter(|| {
|
||||
fast_integer_sum(v.clone().step_by(2))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn step_range_10(c: &mut Criterion) {
|
||||
let v = black_box(0..1024);
|
||||
|
||||
c.bench_function("step range 10", move |b| {
|
||||
b.iter(|| {
|
||||
fast_integer_sum(v.clone().step_by(10))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn cartesian_product_iterator(c: &mut Criterion) {
|
||||
let xs = vec![0; 16];
|
||||
|
||||
c.bench_function("cartesian product iterator", move |b| {
|
||||
b.iter(|| {
|
||||
let mut sum = 0;
|
||||
for (&x, &y, &z) in iproduct!(&xs, &xs, &xs) {
|
||||
sum += x;
|
||||
sum += y;
|
||||
sum += z;
|
||||
}
|
||||
sum
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn cartesian_product_fold(c: &mut Criterion) {
|
||||
let xs = vec![0; 16];
|
||||
|
||||
c.bench_function("cartesian product fold", move |b| {
|
||||
b.iter(|| {
|
||||
let mut sum = 0;
|
||||
iproduct!(&xs, &xs, &xs).fold((), |(), (&x, &y, &z)| {
|
||||
sum += x;
|
||||
sum += y;
|
||||
sum += z;
|
||||
});
|
||||
sum
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn multi_cartesian_product_iterator(c: &mut Criterion) {
|
||||
let xs = [vec![0; 16], vec![0; 16], vec![0; 16]];
|
||||
|
||||
c.bench_function("multi cartesian product iterator", move |b| {
|
||||
b.iter(|| {
|
||||
let mut sum = 0;
|
||||
for x in xs.iter().multi_cartesian_product() {
|
||||
sum += x[0];
|
||||
sum += x[1];
|
||||
sum += x[2];
|
||||
}
|
||||
sum
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn multi_cartesian_product_fold(c: &mut Criterion) {
|
||||
let xs = [vec![0; 16], vec![0; 16], vec![0; 16]];
|
||||
|
||||
c.bench_function("multi cartesian product fold", move |b| {
|
||||
b.iter(|| {
|
||||
let mut sum = 0;
|
||||
xs.iter().multi_cartesian_product().fold((), |(), x| {
|
||||
sum += x[0];
|
||||
sum += x[1];
|
||||
sum += x[2];
|
||||
});
|
||||
sum
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn cartesian_product_nested_for(c: &mut Criterion) {
|
||||
let xs = vec![0; 16];
|
||||
|
||||
c.bench_function("cartesian product nested for", move |b| {
|
||||
b.iter(|| {
|
||||
let mut sum = 0;
|
||||
for &x in &xs {
|
||||
for &y in &xs {
|
||||
for &z in &xs {
|
||||
sum += x;
|
||||
sum += y;
|
||||
sum += z;
|
||||
}
|
||||
}
|
||||
}
|
||||
sum
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn all_equal(c: &mut Criterion) {
|
||||
let mut xs = vec![0; 5_000_000];
|
||||
xs.extend(vec![1; 5_000_000]);
|
||||
|
||||
c.bench_function("all equal", move |b| {
|
||||
b.iter(|| xs.iter().all_equal())
|
||||
});
|
||||
}
|
||||
|
||||
fn all_equal_for(c: &mut Criterion) {
|
||||
let mut xs = vec![0; 5_000_000];
|
||||
xs.extend(vec![1; 5_000_000]);
|
||||
|
||||
c.bench_function("all equal for", move |b| {
|
||||
b.iter(|| {
|
||||
for &x in &xs {
|
||||
if x != xs[0] {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn all_equal_default(c: &mut Criterion) {
|
||||
let mut xs = vec![0; 5_000_000];
|
||||
xs.extend(vec![1; 5_000_000]);
|
||||
|
||||
c.bench_function("all equal default", move |b| {
|
||||
b.iter(|| xs.iter().dedup().nth(1).is_none())
|
||||
});
|
||||
}
|
||||
|
||||
const PERM_COUNT: usize = 6;
|
||||
|
||||
fn permutations_iter(c: &mut Criterion) {
|
||||
struct NewIterator(Range<usize>);
|
||||
|
||||
impl Iterator for NewIterator {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.0.next()
|
||||
}
|
||||
}
|
||||
|
||||
c.bench_function("permutations iter", move |b| {
|
||||
b.iter(|| {
|
||||
for _ in NewIterator(0..PERM_COUNT).permutations(PERM_COUNT) {
|
||||
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn permutations_range(c: &mut Criterion) {
|
||||
c.bench_function("permutations range", move |b| {
|
||||
b.iter(|| {
|
||||
for _ in (0..PERM_COUNT).permutations(PERM_COUNT) {
|
||||
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn permutations_slice(c: &mut Criterion) {
|
||||
let v = (0..PERM_COUNT).collect_vec();
|
||||
|
||||
c.bench_function("permutations slice", move |b| {
|
||||
b.iter(|| {
|
||||
for _ in v.as_slice().iter().permutations(PERM_COUNT) {
|
||||
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
slice_iter,
|
||||
slice_iter_rev,
|
||||
zip_default_zip,
|
||||
zipdot_i32_default_zip,
|
||||
zipdot_f32_default_zip,
|
||||
zip_default_zip3,
|
||||
zip_slices_ziptuple,
|
||||
zipslices,
|
||||
zipslices_mut,
|
||||
zipdot_i32_zipslices,
|
||||
zipdot_f32_zipslices,
|
||||
zip_checked_counted_loop,
|
||||
zipdot_i32_checked_counted_loop,
|
||||
zipdot_f32_checked_counted_loop,
|
||||
zipdot_f32_checked_counted_unrolled_loop,
|
||||
zip_unchecked_counted_loop,
|
||||
zipdot_i32_unchecked_counted_loop,
|
||||
zipdot_f32_unchecked_counted_loop,
|
||||
zip_unchecked_counted_loop3,
|
||||
group_by_lazy_1,
|
||||
group_by_lazy_2,
|
||||
slice_chunks,
|
||||
chunks_lazy_1,
|
||||
equal,
|
||||
merge_default,
|
||||
merge_by_cmp,
|
||||
merge_by_lt,
|
||||
kmerge_default,
|
||||
kmerge_tenway,
|
||||
step_vec_2,
|
||||
step_vec_10,
|
||||
step_range_2,
|
||||
step_range_10,
|
||||
cartesian_product_iterator,
|
||||
cartesian_product_fold,
|
||||
multi_cartesian_product_iterator,
|
||||
multi_cartesian_product_fold,
|
||||
cartesian_product_nested_for,
|
||||
all_equal,
|
||||
all_equal_for,
|
||||
all_equal_default,
|
||||
permutations_iter,
|
||||
permutations_range,
|
||||
permutations_slice,
|
||||
);
|
||||
criterion_main!(benches);
|
40
vendor/itertools/benches/combinations_with_replacement.rs
vendored
Normal file
40
vendor/itertools/benches/combinations_with_replacement.rs
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use itertools::Itertools;
|
||||
|
||||
fn comb_replacement_n10_k5(c: &mut Criterion) {
|
||||
c.bench_function("comb replacement n10k5", move |b| {
|
||||
b.iter(|| {
|
||||
for i in (0..10).combinations_with_replacement(5) {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn comb_replacement_n5_k10(c: &mut Criterion) {
|
||||
c.bench_function("comb replacement n5 k10", move |b| {
|
||||
b.iter(|| {
|
||||
for i in (0..5).combinations_with_replacement(10) {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn comb_replacement_n10_k10(c: &mut Criterion) {
|
||||
c.bench_function("comb replacement n10 k10", move |b| {
|
||||
b.iter(|| {
|
||||
for i in (0..10).combinations_with_replacement(10) {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
comb_replacement_n10_k5,
|
||||
comb_replacement_n5_k10,
|
||||
comb_replacement_n10_k10,
|
||||
);
|
||||
criterion_main!(benches);
|
2
vendor/itertools/benches/extra/mod.rs
vendored
Normal file
2
vendor/itertools/benches/extra/mod.rs
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
pub use self::zipslices::ZipSlices;
|
||||
mod zipslices;
|
188
vendor/itertools/benches/extra/zipslices.rs
vendored
Normal file
188
vendor/itertools/benches/extra/zipslices.rs
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
use std::cmp;
|
||||
|
||||
// Note: There are different ways to implement ZipSlices.
|
||||
// This version performed the best in benchmarks.
|
||||
//
|
||||
// I also implemented a version with three pointes (tptr, tend, uptr),
|
||||
// that mimiced slice::Iter and only checked bounds by using tptr == tend,
|
||||
// but that was inferior to this solution.
|
||||
|
||||
/// An iterator which iterates two slices simultaneously.
|
||||
///
|
||||
/// `ZipSlices` acts like a double-ended `.zip()` iterator.
|
||||
///
|
||||
/// It was intended to be more efficient than `.zip()`, and it was, then
|
||||
/// rustc changed how it optimizes so it can not promise improved performance
|
||||
/// at this time.
|
||||
///
|
||||
/// Note that elements past the end of the shortest of the two slices are ignored.
|
||||
///
|
||||
/// Iterator element type for `ZipSlices<T, U>` is `(T::Item, U::Item)`. For example,
|
||||
/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`.
|
||||
#[derive(Clone)]
|
||||
pub struct ZipSlices<T, U> {
|
||||
t: T,
|
||||
u: U,
|
||||
len: usize,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]> {
|
||||
/// Create a new `ZipSlices` from slices `a` and `b`.
|
||||
///
|
||||
/// Act like a double-ended `.zip()` iterator, but more efficiently.
|
||||
///
|
||||
/// Note that elements past the end of the shortest of the two slices are ignored.
|
||||
#[inline(always)]
|
||||
pub fn new(a: &'a [A], b: &'b [B]) -> Self {
|
||||
let minl = cmp::min(a.len(), b.len());
|
||||
ZipSlices {
|
||||
t: a,
|
||||
u: b,
|
||||
len: minl,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ZipSlices<T, U>
|
||||
where T: Slice,
|
||||
U: Slice
|
||||
{
|
||||
/// Create a new `ZipSlices` from slices `a` and `b`.
|
||||
///
|
||||
/// Act like a double-ended `.zip()` iterator, but more efficiently.
|
||||
///
|
||||
/// Note that elements past the end of the shortest of the two slices are ignored.
|
||||
#[inline(always)]
|
||||
pub fn from_slices(a: T, b: U) -> Self {
|
||||
let minl = cmp::min(a.len(), b.len());
|
||||
ZipSlices {
|
||||
t: a,
|
||||
u: b,
|
||||
len: minl,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Iterator for ZipSlices<T, U>
|
||||
where T: Slice,
|
||||
U: Slice
|
||||
{
|
||||
type Item = (T::Item, U::Item);
|
||||
|
||||
#[inline(always)]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
if self.index >= self.len {
|
||||
None
|
||||
} else {
|
||||
let i = self.index;
|
||||
self.index += 1;
|
||||
Some((
|
||||
self.t.get_unchecked(i),
|
||||
self.u.get_unchecked(i)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.len - self.index;
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> DoubleEndedIterator for ZipSlices<T, U>
|
||||
where T: Slice,
|
||||
U: Slice
|
||||
{
|
||||
#[inline(always)]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
if self.index >= self.len {
|
||||
None
|
||||
} else {
|
||||
self.len -= 1;
|
||||
let i = self.len;
|
||||
Some((
|
||||
self.t.get_unchecked(i),
|
||||
self.u.get_unchecked(i)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ExactSizeIterator for ZipSlices<T, U>
|
||||
where T: Slice,
|
||||
U: Slice
|
||||
{}
|
||||
|
||||
unsafe impl<T, U> Slice for ZipSlices<T, U>
|
||||
where T: Slice,
|
||||
U: Slice
|
||||
{
|
||||
type Item = (T::Item, U::Item);
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.len - self.index
|
||||
}
|
||||
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
|
||||
(self.t.get_unchecked(i),
|
||||
self.u.get_unchecked(i))
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`.
|
||||
///
|
||||
/// Unsafe trait because:
|
||||
///
|
||||
/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`.
|
||||
pub unsafe trait Slice {
|
||||
/// The type of a reference to the slice's elements
|
||||
type Item;
|
||||
#[doc(hidden)]
|
||||
fn len(&self) -> usize;
|
||||
#[doc(hidden)]
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item;
|
||||
}
|
||||
|
||||
unsafe impl<'a, T> Slice for &'a [T] {
|
||||
type Item = &'a T;
|
||||
#[inline(always)]
|
||||
fn len(&self) -> usize { (**self).len() }
|
||||
#[inline(always)]
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> &'a T {
|
||||
debug_assert!(i < self.len());
|
||||
(**self).get_unchecked(i)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, T> Slice for &'a mut [T] {
|
||||
type Item = &'a mut T;
|
||||
#[inline(always)]
|
||||
fn len(&self) -> usize { (**self).len() }
|
||||
#[inline(always)]
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T {
|
||||
debug_assert!(i < self.len());
|
||||
// override the lifetime constraints of &mut &'a mut [T]
|
||||
(*(*self as *mut [T])).get_unchecked_mut(i)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zipslices() {
|
||||
|
||||
let xs = [1, 2, 3, 4, 5, 6];
|
||||
let ys = [1, 2, 3, 7];
|
||||
::itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys));
|
||||
|
||||
let xs = [1, 2, 3, 4, 5, 6];
|
||||
let mut ys = [0; 6];
|
||||
for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) {
|
||||
*y = *x;
|
||||
}
|
||||
::itertools::assert_equal(&xs, &ys);
|
||||
}
|
73
vendor/itertools/benches/fold_specialization.rs
vendored
Normal file
73
vendor/itertools/benches/fold_specialization.rs
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use itertools::Itertools;
|
||||
|
||||
struct Unspecialized<I>(I);
|
||||
|
||||
impl<I> Iterator for Unspecialized<I>
|
||||
where I: Iterator
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
#[inline(always)]
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
self.0.next()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
mod specialization {
|
||||
use super::*;
|
||||
|
||||
pub mod intersperse {
|
||||
use super::*;
|
||||
|
||||
pub fn external(c: &mut Criterion)
|
||||
{
|
||||
let arr = [1; 1024];
|
||||
|
||||
c.bench_function("external", move |b| {
|
||||
b.iter(|| {
|
||||
let mut sum = 0;
|
||||
for &x in arr.iter().intersperse(&0) {
|
||||
sum += x;
|
||||
}
|
||||
sum
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub fn internal_specialized(c: &mut Criterion)
|
||||
{
|
||||
let arr = [1; 1024];
|
||||
|
||||
c.bench_function("internal specialized", move |b| {
|
||||
b.iter(|| {
|
||||
arr.iter().intersperse(&0).fold(0, |acc, x| acc + x)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub fn internal_unspecialized(c: &mut Criterion)
|
||||
{
|
||||
let arr = [1; 1024];
|
||||
|
||||
c.bench_function("internal unspecialized", move |b| {
|
||||
b.iter(|| {
|
||||
Unspecialized(arr.iter().intersperse(&0)).fold(0, |acc, x| acc + x)
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
specialization::intersperse::external,
|
||||
specialization::intersperse::internal_specialized,
|
||||
specialization::intersperse::internal_unspecialized,
|
||||
);
|
||||
criterion_main!(benches);
|
144
vendor/itertools/benches/tree_fold1.rs
vendored
Normal file
144
vendor/itertools/benches/tree_fold1.rs
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use itertools::{Itertools, cloned};
|
||||
|
||||
trait IterEx : Iterator {
|
||||
// Another efficient implementation against which to compare,
|
||||
// but needs `std` so is less desirable.
|
||||
fn tree_fold1_vec<F>(self, mut f: F) -> Option<Self::Item>
|
||||
where F: FnMut(Self::Item, Self::Item) -> Self::Item,
|
||||
Self: Sized,
|
||||
{
|
||||
let hint = self.size_hint().0;
|
||||
let cap = std::mem::size_of::<usize>() * 8 - hint.leading_zeros() as usize;
|
||||
let mut stack = Vec::with_capacity(cap);
|
||||
self.enumerate().for_each(|(mut i, mut x)| {
|
||||
while (i & 1) != 0 {
|
||||
x = f(stack.pop().unwrap(), x);
|
||||
i >>= 1;
|
||||
}
|
||||
stack.push(x);
|
||||
});
|
||||
stack.into_iter().fold1(f)
|
||||
}
|
||||
}
|
||||
impl<T:Iterator> IterEx for T {}
|
||||
|
||||
macro_rules! def_benchs {
|
||||
($N:expr,
|
||||
$FUN:ident,
|
||||
$BENCH_NAME:ident,
|
||||
) => (
|
||||
mod $BENCH_NAME {
|
||||
use super::*;
|
||||
|
||||
pub fn sum(c: &mut Criterion) {
|
||||
let v: Vec<u32> = (0.. $N).collect();
|
||||
|
||||
c.bench_function(&(stringify!($BENCH_NAME).replace('_', " ") + " sum"), move |b| {
|
||||
b.iter(|| {
|
||||
cloned(&v).$FUN(|x, y| x + y)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub fn complex_iter(c: &mut Criterion) {
|
||||
let u = (3..).take($N / 2);
|
||||
let v = (5..).take($N / 2);
|
||||
let it = u.chain(v);
|
||||
|
||||
c.bench_function(&(stringify!($BENCH_NAME).replace('_', " ") + " complex iter"), move |b| {
|
||||
b.iter(|| {
|
||||
it.clone().map(|x| x as f32).$FUN(f32::atan2)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub fn string_format(c: &mut Criterion) {
|
||||
// This goes quadratic with linear `fold1`, so use a smaller
|
||||
// size to not waste too much time in travis. The allocations
|
||||
// in here are so expensive anyway that it'll still take
|
||||
// way longer per iteration than the other two benchmarks.
|
||||
let v: Vec<u32> = (0.. ($N/4)).collect();
|
||||
|
||||
c.bench_function(&(stringify!($BENCH_NAME).replace('_', " ") + " string format"), move |b| {
|
||||
b.iter(|| {
|
||||
cloned(&v).map(|x| x.to_string()).$FUN(|x, y| format!("{} + {}", x, y))
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
$BENCH_NAME,
|
||||
$BENCH_NAME::sum,
|
||||
$BENCH_NAME::complex_iter,
|
||||
$BENCH_NAME::string_format,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
10_000,
|
||||
fold1,
|
||||
fold1_10k,
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
10_000,
|
||||
tree_fold1,
|
||||
tree_fold1_stack_10k,
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
10_000,
|
||||
tree_fold1_vec,
|
||||
tree_fold1_vec_10k,
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
100,
|
||||
fold1,
|
||||
fold1_100,
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
100,
|
||||
tree_fold1,
|
||||
tree_fold1_stack_100,
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
100,
|
||||
tree_fold1_vec,
|
||||
tree_fold1_vec_100,
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
8,
|
||||
fold1,
|
||||
fold1_08,
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
8,
|
||||
tree_fold1,
|
||||
tree_fold1_stack_08,
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
8,
|
||||
tree_fold1_vec,
|
||||
tree_fold1_vec_08,
|
||||
}
|
||||
|
||||
criterion_main!(
|
||||
fold1_10k,
|
||||
tree_fold1_stack_10k,
|
||||
tree_fold1_vec_10k,
|
||||
fold1_100,
|
||||
tree_fold1_stack_100,
|
||||
tree_fold1_vec_100,
|
||||
fold1_08,
|
||||
tree_fold1_stack_08,
|
||||
tree_fold1_vec_08,
|
||||
);
|
113
vendor/itertools/benches/tuple_combinations.rs
vendored
Normal file
113
vendor/itertools/benches/tuple_combinations.rs
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use itertools::Itertools;
|
||||
|
||||
// approximate 100_000 iterations for each combination
|
||||
const N1: usize = 100_000;
|
||||
const N2: usize = 448;
|
||||
const N3: usize = 86;
|
||||
const N4: usize = 41;
|
||||
|
||||
fn comb_for1(c: &mut Criterion) {
|
||||
c.bench_function("comb for1", move |b| {
|
||||
b.iter(|| {
|
||||
for i in 0..N1 {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn comb_for2(c: &mut Criterion) {
|
||||
c.bench_function("comb for2", move |b| {
|
||||
b.iter(|| {
|
||||
for i in 0..N2 {
|
||||
for j in (i + 1)..N2 {
|
||||
black_box(i + j);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn comb_for3(c: &mut Criterion) {
|
||||
c.bench_function("comb for3", move |b| {
|
||||
b.iter(|| {
|
||||
for i in 0..N3 {
|
||||
for j in (i + 1)..N3 {
|
||||
for k in (j + 1)..N3 {
|
||||
black_box(i + j + k);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn comb_for4(c: &mut Criterion) {
|
||||
c.bench_function("comb for4", move |b| {
|
||||
b.iter(|| {
|
||||
for i in 0..N4 {
|
||||
for j in (i + 1)..N4 {
|
||||
for k in (j + 1)..N4 {
|
||||
for l in (k + 1)..N4 {
|
||||
black_box(i + j + k + l);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn comb_c1(c: &mut Criterion) {
|
||||
c.bench_function("comb c1", move |b| {
|
||||
b.iter(|| {
|
||||
for (i,) in (0..N1).tuple_combinations() {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn comb_c2(c: &mut Criterion) {
|
||||
c.bench_function("comb c2", move |b| {
|
||||
b.iter(|| {
|
||||
for (i, j) in (0..N2).tuple_combinations() {
|
||||
black_box(i + j);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn comb_c3(c: &mut Criterion) {
|
||||
c.bench_function("comb c3", move |b| {
|
||||
b.iter(|| {
|
||||
for (i, j, k) in (0..N3).tuple_combinations() {
|
||||
black_box(i + j + k);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn comb_c4(c: &mut Criterion) {
|
||||
c.bench_function("comb c4", move |b| {
|
||||
b.iter(|| {
|
||||
for (i, j, k, l) in (0..N4).tuple_combinations() {
|
||||
black_box(i + j + k + l);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
comb_for1,
|
||||
comb_for2,
|
||||
comb_for3,
|
||||
comb_for4,
|
||||
comb_c1,
|
||||
comb_c2,
|
||||
comb_c3,
|
||||
comb_c4,
|
||||
);
|
||||
criterion_main!(benches);
|
213
vendor/itertools/benches/tuples.rs
vendored
Normal file
213
vendor/itertools/benches/tuples.rs
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use itertools::Itertools;
|
||||
|
||||
fn s1(a: u32) -> u32 {
|
||||
a
|
||||
}
|
||||
|
||||
fn s2(a: u32, b: u32) -> u32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
fn s3(a: u32, b: u32, c: u32) -> u32 {
|
||||
a + b + c
|
||||
}
|
||||
|
||||
fn s4(a: u32, b: u32, c: u32, d: u32) -> u32 {
|
||||
a + b + c + d
|
||||
}
|
||||
|
||||
fn sum_s1(s: &[u32]) -> u32 {
|
||||
s1(s[0])
|
||||
}
|
||||
|
||||
fn sum_s2(s: &[u32]) -> u32 {
|
||||
s2(s[0], s[1])
|
||||
}
|
||||
|
||||
fn sum_s3(s: &[u32]) -> u32 {
|
||||
s3(s[0], s[1], s[2])
|
||||
}
|
||||
|
||||
fn sum_s4(s: &[u32]) -> u32 {
|
||||
s4(s[0], s[1], s[2], s[3])
|
||||
}
|
||||
|
||||
fn sum_t1(s: &(&u32, )) -> u32 {
|
||||
s1(*s.0)
|
||||
}
|
||||
|
||||
fn sum_t2(s: &(&u32, &u32)) -> u32 {
|
||||
s2(*s.0, *s.1)
|
||||
}
|
||||
|
||||
fn sum_t3(s: &(&u32, &u32, &u32)) -> u32 {
|
||||
s3(*s.0, *s.1, *s.2)
|
||||
}
|
||||
|
||||
fn sum_t4(s: &(&u32, &u32, &u32, &u32)) -> u32 {
|
||||
s4(*s.0, *s.1, *s.2, *s.3)
|
||||
}
|
||||
|
||||
macro_rules! def_benchs {
|
||||
($N:expr;
|
||||
$BENCH_GROUP:ident,
|
||||
$TUPLE_FUN:ident,
|
||||
$TUPLES:ident,
|
||||
$TUPLE_WINDOWS:ident;
|
||||
$SLICE_FUN:ident,
|
||||
$CHUNKS:ident,
|
||||
$WINDOWS:ident;
|
||||
$FOR_CHUNKS:ident,
|
||||
$FOR_WINDOWS:ident
|
||||
) => (
|
||||
fn $FOR_CHUNKS(c: &mut Criterion) {
|
||||
let v: Vec<u32> = (0.. $N * 1_000).collect();
|
||||
let mut s = 0;
|
||||
c.bench_function(&stringify!($FOR_CHUNKS).replace('_', " "), move |b| {
|
||||
b.iter(|| {
|
||||
let mut j = 0;
|
||||
for _ in 0..1_000 {
|
||||
s += $SLICE_FUN(&v[j..(j + $N)]);
|
||||
j += $N;
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn $FOR_WINDOWS(c: &mut Criterion) {
|
||||
let v: Vec<u32> = (0..1_000).collect();
|
||||
let mut s = 0;
|
||||
c.bench_function(&stringify!($FOR_WINDOWS).replace('_', " "), move |b| {
|
||||
b.iter(|| {
|
||||
for i in 0..(1_000 - $N) {
|
||||
s += $SLICE_FUN(&v[i..(i + $N)]);
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn $TUPLES(c: &mut Criterion) {
|
||||
let v: Vec<u32> = (0.. $N * 1_000).collect();
|
||||
let mut s = 0;
|
||||
c.bench_function(&stringify!($TUPLES).replace('_', " "), move |b| {
|
||||
b.iter(|| {
|
||||
for x in v.iter().tuples() {
|
||||
s += $TUPLE_FUN(&x);
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn $CHUNKS(c: &mut Criterion) {
|
||||
let v: Vec<u32> = (0.. $N * 1_000).collect();
|
||||
let mut s = 0;
|
||||
c.bench_function(&stringify!($CHUNKS).replace('_', " "), move |b| {
|
||||
b.iter(|| {
|
||||
for x in v.chunks($N) {
|
||||
s += $SLICE_FUN(x);
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn $TUPLE_WINDOWS(c: &mut Criterion) {
|
||||
let v: Vec<u32> = (0..1_000).collect();
|
||||
let mut s = 0;
|
||||
c.bench_function(&stringify!($TUPLE_WINDOWS).replace('_', " "), move |b| {
|
||||
b.iter(|| {
|
||||
for x in v.iter().tuple_windows() {
|
||||
s += $TUPLE_FUN(&x);
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn $WINDOWS(c: &mut Criterion) {
|
||||
let v: Vec<u32> = (0..1_000).collect();
|
||||
let mut s = 0;
|
||||
c.bench_function(&stringify!($WINDOWS).replace('_', " "), move |b| {
|
||||
b.iter(|| {
|
||||
for x in v.windows($N) {
|
||||
s += $SLICE_FUN(x);
|
||||
}
|
||||
s
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
$BENCH_GROUP,
|
||||
$FOR_CHUNKS,
|
||||
$FOR_WINDOWS,
|
||||
$TUPLES,
|
||||
$CHUNKS,
|
||||
$TUPLE_WINDOWS,
|
||||
$WINDOWS,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
1;
|
||||
benches_1,
|
||||
sum_t1,
|
||||
tuple_chunks_1,
|
||||
tuple_windows_1;
|
||||
sum_s1,
|
||||
slice_chunks_1,
|
||||
slice_windows_1;
|
||||
for_chunks_1,
|
||||
for_windows_1
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
2;
|
||||
benches_2,
|
||||
sum_t2,
|
||||
tuple_chunks_2,
|
||||
tuple_windows_2;
|
||||
sum_s2,
|
||||
slice_chunks_2,
|
||||
slice_windows_2;
|
||||
for_chunks_2,
|
||||
for_windows_2
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
3;
|
||||
benches_3,
|
||||
sum_t3,
|
||||
tuple_chunks_3,
|
||||
tuple_windows_3;
|
||||
sum_s3,
|
||||
slice_chunks_3,
|
||||
slice_windows_3;
|
||||
for_chunks_3,
|
||||
for_windows_3
|
||||
}
|
||||
|
||||
def_benchs!{
|
||||
4;
|
||||
benches_4,
|
||||
sum_t4,
|
||||
tuple_chunks_4,
|
||||
tuple_windows_4;
|
||||
sum_s4,
|
||||
slice_chunks_4,
|
||||
slice_windows_4;
|
||||
for_chunks_4,
|
||||
for_windows_4
|
||||
}
|
||||
|
||||
criterion_main!(
|
||||
benches_1,
|
||||
benches_2,
|
||||
benches_3,
|
||||
benches_4,
|
||||
);
|
150
vendor/itertools/examples/iris.data
vendored
Normal file
150
vendor/itertools/examples/iris.data
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
5.1,3.5,1.4,0.2,Iris-setosa
|
||||
4.9,3.0,1.4,0.2,Iris-setosa
|
||||
4.7,3.2,1.3,0.2,Iris-setosa
|
||||
4.6,3.1,1.5,0.2,Iris-setosa
|
||||
5.0,3.6,1.4,0.2,Iris-setosa
|
||||
5.4,3.9,1.7,0.4,Iris-setosa
|
||||
4.6,3.4,1.4,0.3,Iris-setosa
|
||||
5.0,3.4,1.5,0.2,Iris-setosa
|
||||
4.4,2.9,1.4,0.2,Iris-setosa
|
||||
4.9,3.1,1.5,0.1,Iris-setosa
|
||||
5.4,3.7,1.5,0.2,Iris-setosa
|
||||
4.8,3.4,1.6,0.2,Iris-setosa
|
||||
4.8,3.0,1.4,0.1,Iris-setosa
|
||||
4.3,3.0,1.1,0.1,Iris-setosa
|
||||
5.8,4.0,1.2,0.2,Iris-setosa
|
||||
5.7,4.4,1.5,0.4,Iris-setosa
|
||||
5.4,3.9,1.3,0.4,Iris-setosa
|
||||
5.1,3.5,1.4,0.3,Iris-setosa
|
||||
5.7,3.8,1.7,0.3,Iris-setosa
|
||||
5.1,3.8,1.5,0.3,Iris-setosa
|
||||
5.4,3.4,1.7,0.2,Iris-setosa
|
||||
5.1,3.7,1.5,0.4,Iris-setosa
|
||||
4.6,3.6,1.0,0.2,Iris-setosa
|
||||
5.1,3.3,1.7,0.5,Iris-setosa
|
||||
4.8,3.4,1.9,0.2,Iris-setosa
|
||||
5.0,3.0,1.6,0.2,Iris-setosa
|
||||
5.0,3.4,1.6,0.4,Iris-setosa
|
||||
5.2,3.5,1.5,0.2,Iris-setosa
|
||||
5.2,3.4,1.4,0.2,Iris-setosa
|
||||
4.7,3.2,1.6,0.2,Iris-setosa
|
||||
4.8,3.1,1.6,0.2,Iris-setosa
|
||||
5.4,3.4,1.5,0.4,Iris-setosa
|
||||
5.2,4.1,1.5,0.1,Iris-setosa
|
||||
5.5,4.2,1.4,0.2,Iris-setosa
|
||||
4.9,3.1,1.5,0.1,Iris-setosa
|
||||
5.0,3.2,1.2,0.2,Iris-setosa
|
||||
5.5,3.5,1.3,0.2,Iris-setosa
|
||||
4.9,3.1,1.5,0.1,Iris-setosa
|
||||
4.4,3.0,1.3,0.2,Iris-setosa
|
||||
5.1,3.4,1.5,0.2,Iris-setosa
|
||||
5.0,3.5,1.3,0.3,Iris-setosa
|
||||
4.5,2.3,1.3,0.3,Iris-setosa
|
||||
4.4,3.2,1.3,0.2,Iris-setosa
|
||||
5.0,3.5,1.6,0.6,Iris-setosa
|
||||
5.1,3.8,1.9,0.4,Iris-setosa
|
||||
4.8,3.0,1.4,0.3,Iris-setosa
|
||||
5.1,3.8,1.6,0.2,Iris-setosa
|
||||
4.6,3.2,1.4,0.2,Iris-setosa
|
||||
5.3,3.7,1.5,0.2,Iris-setosa
|
||||
5.0,3.3,1.4,0.2,Iris-setosa
|
||||
7.0,3.2,4.7,1.4,Iris-versicolor
|
||||
6.4,3.2,4.5,1.5,Iris-versicolor
|
||||
6.9,3.1,4.9,1.5,Iris-versicolor
|
||||
5.5,2.3,4.0,1.3,Iris-versicolor
|
||||
6.5,2.8,4.6,1.5,Iris-versicolor
|
||||
5.7,2.8,4.5,1.3,Iris-versicolor
|
||||
6.3,3.3,4.7,1.6,Iris-versicolor
|
||||
4.9,2.4,3.3,1.0,Iris-versicolor
|
||||
6.6,2.9,4.6,1.3,Iris-versicolor
|
||||
5.2,2.7,3.9,1.4,Iris-versicolor
|
||||
5.0,2.0,3.5,1.0,Iris-versicolor
|
||||
5.9,3.0,4.2,1.5,Iris-versicolor
|
||||
6.0,2.2,4.0,1.0,Iris-versicolor
|
||||
6.1,2.9,4.7,1.4,Iris-versicolor
|
||||
5.6,2.9,3.6,1.3,Iris-versicolor
|
||||
6.7,3.1,4.4,1.4,Iris-versicolor
|
||||
5.6,3.0,4.5,1.5,Iris-versicolor
|
||||
5.8,2.7,4.1,1.0,Iris-versicolor
|
||||
6.2,2.2,4.5,1.5,Iris-versicolor
|
||||
5.6,2.5,3.9,1.1,Iris-versicolor
|
||||
5.9,3.2,4.8,1.8,Iris-versicolor
|
||||
6.1,2.8,4.0,1.3,Iris-versicolor
|
||||
6.3,2.5,4.9,1.5,Iris-versicolor
|
||||
6.1,2.8,4.7,1.2,Iris-versicolor
|
||||
6.4,2.9,4.3,1.3,Iris-versicolor
|
||||
6.6,3.0,4.4,1.4,Iris-versicolor
|
||||
6.8,2.8,4.8,1.4,Iris-versicolor
|
||||
6.7,3.0,5.0,1.7,Iris-versicolor
|
||||
6.0,2.9,4.5,1.5,Iris-versicolor
|
||||
5.7,2.6,3.5,1.0,Iris-versicolor
|
||||
5.5,2.4,3.8,1.1,Iris-versicolor
|
||||
5.5,2.4,3.7,1.0,Iris-versicolor
|
||||
5.8,2.7,3.9,1.2,Iris-versicolor
|
||||
6.0,2.7,5.1,1.6,Iris-versicolor
|
||||
5.4,3.0,4.5,1.5,Iris-versicolor
|
||||
6.0,3.4,4.5,1.6,Iris-versicolor
|
||||
6.7,3.1,4.7,1.5,Iris-versicolor
|
||||
6.3,2.3,4.4,1.3,Iris-versicolor
|
||||
5.6,3.0,4.1,1.3,Iris-versicolor
|
||||
5.5,2.5,4.0,1.3,Iris-versicolor
|
||||
5.5,2.6,4.4,1.2,Iris-versicolor
|
||||
6.1,3.0,4.6,1.4,Iris-versicolor
|
||||
5.8,2.6,4.0,1.2,Iris-versicolor
|
||||
5.0,2.3,3.3,1.0,Iris-versicolor
|
||||
5.6,2.7,4.2,1.3,Iris-versicolor
|
||||
5.7,3.0,4.2,1.2,Iris-versicolor
|
||||
5.7,2.9,4.2,1.3,Iris-versicolor
|
||||
6.2,2.9,4.3,1.3,Iris-versicolor
|
||||
5.1,2.5,3.0,1.1,Iris-versicolor
|
||||
5.7,2.8,4.1,1.3,Iris-versicolor
|
||||
6.3,3.3,6.0,2.5,Iris-virginica
|
||||
5.8,2.7,5.1,1.9,Iris-virginica
|
||||
7.1,3.0,5.9,2.1,Iris-virginica
|
||||
6.3,2.9,5.6,1.8,Iris-virginica
|
||||
6.5,3.0,5.8,2.2,Iris-virginica
|
||||
7.6,3.0,6.6,2.1,Iris-virginica
|
||||
4.9,2.5,4.5,1.7,Iris-virginica
|
||||
7.3,2.9,6.3,1.8,Iris-virginica
|
||||
6.7,2.5,5.8,1.8,Iris-virginica
|
||||
7.2,3.6,6.1,2.5,Iris-virginica
|
||||
6.5,3.2,5.1,2.0,Iris-virginica
|
||||
6.4,2.7,5.3,1.9,Iris-virginica
|
||||
6.8,3.0,5.5,2.1,Iris-virginica
|
||||
5.7,2.5,5.0,2.0,Iris-virginica
|
||||
5.8,2.8,5.1,2.4,Iris-virginica
|
||||
6.4,3.2,5.3,2.3,Iris-virginica
|
||||
6.5,3.0,5.5,1.8,Iris-virginica
|
||||
7.7,3.8,6.7,2.2,Iris-virginica
|
||||
7.7,2.6,6.9,2.3,Iris-virginica
|
||||
6.0,2.2,5.0,1.5,Iris-virginica
|
||||
6.9,3.2,5.7,2.3,Iris-virginica
|
||||
5.6,2.8,4.9,2.0,Iris-virginica
|
||||
7.7,2.8,6.7,2.0,Iris-virginica
|
||||
6.3,2.7,4.9,1.8,Iris-virginica
|
||||
6.7,3.3,5.7,2.1,Iris-virginica
|
||||
7.2,3.2,6.0,1.8,Iris-virginica
|
||||
6.2,2.8,4.8,1.8,Iris-virginica
|
||||
6.1,3.0,4.9,1.8,Iris-virginica
|
||||
6.4,2.8,5.6,2.1,Iris-virginica
|
||||
7.2,3.0,5.8,1.6,Iris-virginica
|
||||
7.4,2.8,6.1,1.9,Iris-virginica
|
||||
7.9,3.8,6.4,2.0,Iris-virginica
|
||||
6.4,2.8,5.6,2.2,Iris-virginica
|
||||
6.3,2.8,5.1,1.5,Iris-virginica
|
||||
6.1,2.6,5.6,1.4,Iris-virginica
|
||||
7.7,3.0,6.1,2.3,Iris-virginica
|
||||
6.3,3.4,5.6,2.4,Iris-virginica
|
||||
6.4,3.1,5.5,1.8,Iris-virginica
|
||||
6.0,3.0,4.8,1.8,Iris-virginica
|
||||
6.9,3.1,5.4,2.1,Iris-virginica
|
||||
6.7,3.1,5.6,2.4,Iris-virginica
|
||||
6.9,3.1,5.1,2.3,Iris-virginica
|
||||
5.8,2.7,5.1,1.9,Iris-virginica
|
||||
6.8,3.2,5.9,2.3,Iris-virginica
|
||||
6.7,3.3,5.7,2.5,Iris-virginica
|
||||
6.7,3.0,5.2,2.3,Iris-virginica
|
||||
6.3,2.5,5.0,1.9,Iris-virginica
|
||||
6.5,3.0,5.2,2.0,Iris-virginica
|
||||
6.2,3.4,5.4,2.3,Iris-virginica
|
||||
5.9,3.0,5.1,1.8,Iris-virginica
|
137
vendor/itertools/examples/iris.rs
vendored
Normal file
137
vendor/itertools/examples/iris.rs
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
///
|
||||
/// This example parses, sorts and groups the iris dataset
|
||||
/// and does some simple manipulations.
|
||||
///
|
||||
/// Iterators and itertools functionality are used throughout.
|
||||
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
use std::iter::repeat;
|
||||
use std::num::ParseFloatError;
|
||||
use std::str::FromStr;
|
||||
|
||||
static DATA: &'static str = include_str!("iris.data");
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Iris {
|
||||
name: String,
|
||||
data: [f32; 4],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum ParseError {
|
||||
Numeric(ParseFloatError),
|
||||
Other(&'static str),
|
||||
}
|
||||
|
||||
impl From<ParseFloatError> for ParseError {
|
||||
fn from(err: ParseFloatError) -> Self {
|
||||
ParseError::Numeric(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse an Iris from a comma-separated line
|
||||
impl FromStr for Iris {
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut iris = Iris { name: "".into(), data: [0.; 4] };
|
||||
let mut parts = s.split(",").map(str::trim);
|
||||
|
||||
// using Iterator::by_ref()
|
||||
for (index, part) in parts.by_ref().take(4).enumerate() {
|
||||
iris.data[index] = part.parse::<f32>()?;
|
||||
}
|
||||
if let Some(name) = parts.next() {
|
||||
iris.name = name.into();
|
||||
} else {
|
||||
return Err(ParseError::Other("Missing name"))
|
||||
}
|
||||
Ok(iris)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// using Itertools::fold_results to create the result of parsing
|
||||
let irises = DATA.lines()
|
||||
.map(str::parse)
|
||||
.fold_results(Vec::new(), |mut v, iris: Iris| {
|
||||
v.push(iris);
|
||||
v
|
||||
});
|
||||
let mut irises = match irises {
|
||||
Err(e) => {
|
||||
println!("Error parsing: {:?}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(data) => data,
|
||||
};
|
||||
|
||||
// Sort them and group them
|
||||
irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));
|
||||
|
||||
// using Iterator::cycle()
|
||||
let mut plot_symbols = "+ox".chars().cycle();
|
||||
let mut symbolmap = HashMap::new();
|
||||
|
||||
// using Itertools::group_by
|
||||
for (species, species_group) in &irises.iter().group_by(|iris| &iris.name) {
|
||||
// assign a plot symbol
|
||||
symbolmap.entry(species).or_insert_with(|| {
|
||||
plot_symbols.next().unwrap()
|
||||
});
|
||||
println!("{} (symbol={})", species, symbolmap[species]);
|
||||
|
||||
for iris in species_group {
|
||||
// using Itertools::format for lazy formatting
|
||||
println!("{:>3.1}", iris.data.iter().format(", "));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Look at all combinations of the four columns
|
||||
//
|
||||
// See https://en.wikipedia.org/wiki/Iris_flower_data_set
|
||||
//
|
||||
let n = 30; // plot size
|
||||
let mut plot = vec![' '; n * n];
|
||||
|
||||
// using Itertools::tuple_combinations
|
||||
for (a, b) in (0..4).tuple_combinations() {
|
||||
println!("Column {} vs {}:", a, b);
|
||||
|
||||
// Clear plot
|
||||
//
|
||||
// using std::iter::repeat;
|
||||
// using Itertools::set_from
|
||||
plot.iter_mut().set_from(repeat(' '));
|
||||
|
||||
// using Itertools::minmax
|
||||
let min_max = |data: &[Iris], col| {
|
||||
data.iter()
|
||||
.map(|iris| iris.data[col])
|
||||
.minmax()
|
||||
.into_option()
|
||||
.expect("Can't find min/max of empty iterator")
|
||||
};
|
||||
let (min_x, max_x) = min_max(&irises, a);
|
||||
let (min_y, max_y) = min_max(&irises, b);
|
||||
|
||||
// Plot the data points
|
||||
let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n - 1) as f32)) as usize;
|
||||
let flip = |ix| n - 1 - ix; // reverse axis direction
|
||||
|
||||
for iris in &irises {
|
||||
let ix = round_to_grid(iris.data[a], min_x, max_x);
|
||||
let iy = flip(round_to_grid(iris.data[b], min_y, max_y));
|
||||
plot[n * iy + ix] = symbolmap[&iris.name];
|
||||
}
|
||||
|
||||
// render plot
|
||||
//
|
||||
// using Itertools::join
|
||||
for line in plot.chunks(n) {
|
||||
println!("{}", line.iter().join(" "))
|
||||
}
|
||||
}
|
||||
}
|
1260
vendor/itertools/src/adaptors/mod.rs
vendored
Normal file
1260
vendor/itertools/src/adaptors/mod.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
220
vendor/itertools/src/adaptors/multi_product.rs
vendored
Normal file
220
vendor/itertools/src/adaptors/multi_product.rs
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
#![cfg(feature = "use_std")]
|
||||
|
||||
use crate::size_hint;
|
||||
use crate::Itertools;
|
||||
|
||||
#[derive(Clone)]
|
||||
/// An iterator adaptor that iterates over the cartesian product of
|
||||
/// multiple iterators of type `I`.
|
||||
///
|
||||
/// An iterator element type is `Vec<I>`.
|
||||
///
|
||||
/// See [`.multi_cartesian_product()`](../trait.Itertools.html#method.multi_cartesian_product)
|
||||
/// for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct MultiProduct<I>(Vec<MultiProductIter<I>>)
|
||||
where I: Iterator + Clone,
|
||||
I::Item: Clone;
|
||||
|
||||
/// Create a new cartesian product iterator over an arbitrary number
|
||||
/// of iterators of the same type.
|
||||
///
|
||||
/// Iterator element is of type `Vec<H::Item::Item>`.
|
||||
pub fn multi_cartesian_product<H>(iters: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter>
|
||||
where H: Iterator,
|
||||
H::Item: IntoIterator,
|
||||
<H::Item as IntoIterator>::IntoIter: Clone,
|
||||
<H::Item as IntoIterator>::Item: Clone
|
||||
{
|
||||
MultiProduct(iters.map(|i| MultiProductIter::new(i.into_iter())).collect())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Holds the state of a single iterator within a MultiProduct.
|
||||
struct MultiProductIter<I>
|
||||
where I: Iterator + Clone,
|
||||
I::Item: Clone
|
||||
{
|
||||
cur: Option<I::Item>,
|
||||
iter: I,
|
||||
iter_orig: I,
|
||||
}
|
||||
|
||||
/// Holds the current state during an iteration of a MultiProduct.
|
||||
#[derive(Debug)]
|
||||
enum MultiProductIterState {
|
||||
StartOfIter,
|
||||
MidIter { on_first_iter: bool },
|
||||
}
|
||||
|
||||
impl<I> MultiProduct<I>
|
||||
where I: Iterator + Clone,
|
||||
I::Item: Clone
|
||||
{
|
||||
/// Iterates the rightmost iterator, then recursively iterates iterators
|
||||
/// to the left if necessary.
|
||||
///
|
||||
/// Returns true if the iteration succeeded, else false.
|
||||
fn iterate_last(
|
||||
multi_iters: &mut [MultiProductIter<I>],
|
||||
mut state: MultiProductIterState
|
||||
) -> bool {
|
||||
use self::MultiProductIterState::*;
|
||||
|
||||
if let Some((last, rest)) = multi_iters.split_last_mut() {
|
||||
let on_first_iter = match state {
|
||||
StartOfIter => {
|
||||
let on_first_iter = !last.in_progress();
|
||||
state = MidIter { on_first_iter };
|
||||
on_first_iter
|
||||
},
|
||||
MidIter { on_first_iter } => on_first_iter
|
||||
};
|
||||
|
||||
if !on_first_iter {
|
||||
last.iterate();
|
||||
}
|
||||
|
||||
if last.in_progress() {
|
||||
true
|
||||
} else if MultiProduct::iterate_last(rest, state) {
|
||||
last.reset();
|
||||
last.iterate();
|
||||
// If iterator is None twice consecutively, then iterator is
|
||||
// empty; whole product is empty.
|
||||
last.in_progress()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
// Reached end of iterator list. On initialisation, return true.
|
||||
// At end of iteration (final iterator finishes), finish.
|
||||
match state {
|
||||
StartOfIter => false,
|
||||
MidIter { on_first_iter } => on_first_iter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the unwrapped value of the next iteration.
|
||||
fn curr_iterator(&self) -> Vec<I::Item> {
|
||||
self.0.iter().map(|multi_iter| {
|
||||
multi_iter.cur.clone().unwrap()
|
||||
}).collect()
|
||||
}
|
||||
|
||||
/// Returns true if iteration has started and has not yet finished; false
|
||||
/// otherwise.
|
||||
fn in_progress(&self) -> bool {
|
||||
if let Some(last) = self.0.last() {
|
||||
last.in_progress()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> MultiProductIter<I>
|
||||
where I: Iterator + Clone,
|
||||
I::Item: Clone
|
||||
{
|
||||
fn new(iter: I) -> Self {
|
||||
MultiProductIter {
|
||||
cur: None,
|
||||
iter: iter.clone(),
|
||||
iter_orig: iter
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate the managed iterator.
|
||||
fn iterate(&mut self) {
|
||||
self.cur = self.iter.next();
|
||||
}
|
||||
|
||||
/// Reset the managed iterator.
|
||||
fn reset(&mut self) {
|
||||
self.iter = self.iter_orig.clone();
|
||||
}
|
||||
|
||||
/// Returns true if the current iterator has been started and has not yet
|
||||
/// finished; false otherwise.
|
||||
fn in_progress(&self) -> bool {
|
||||
self.cur.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for MultiProduct<I>
|
||||
where I: Iterator + Clone,
|
||||
I::Item: Clone
|
||||
{
|
||||
type Item = Vec<I::Item>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if MultiProduct::iterate_last(
|
||||
&mut self.0,
|
||||
MultiProductIterState::StartOfIter
|
||||
) {
|
||||
Some(self.curr_iterator())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
if self.0.len() == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if !self.in_progress() {
|
||||
return self.0.into_iter().fold(1, |acc, multi_iter| {
|
||||
acc * multi_iter.iter.count()
|
||||
});
|
||||
}
|
||||
|
||||
self.0.into_iter().fold(
|
||||
0,
|
||||
|acc, MultiProductIter { iter, iter_orig, cur: _ }| {
|
||||
let total_count = iter_orig.count();
|
||||
let cur_count = iter.count();
|
||||
acc * total_count + cur_count
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
// Not ExactSizeIterator because size may be larger than usize
|
||||
if self.0.len() == 0 {
|
||||
return (0, Some(0));
|
||||
}
|
||||
|
||||
if !self.in_progress() {
|
||||
return self.0.iter().fold((1, Some(1)), |acc, multi_iter| {
|
||||
size_hint::mul(acc, multi_iter.iter.size_hint())
|
||||
});
|
||||
}
|
||||
|
||||
self.0.iter().fold(
|
||||
(0, Some(0)),
|
||||
|acc, &MultiProductIter { ref iter, ref iter_orig, cur: _ }| {
|
||||
let cur_size = iter.size_hint();
|
||||
let total_size = iter_orig.size_hint();
|
||||
size_hint::add(size_hint::mul(acc, total_size), cur_size)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn last(self) -> Option<Self::Item> {
|
||||
let iter_count = self.0.len();
|
||||
|
||||
let lasts: Self::Item = self.0.into_iter()
|
||||
.map(|multi_iter| multi_iter.iter.last())
|
||||
.while_some()
|
||||
.collect();
|
||||
|
||||
if lasts.len() == iter_count {
|
||||
Some(lasts)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
89
vendor/itertools/src/combinations.rs
vendored
Normal file
89
vendor/itertools/src/combinations.rs
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
use std::fmt;
|
||||
|
||||
use super::lazy_buffer::LazyBuffer;
|
||||
|
||||
/// An iterator to iterate through all the `k`-length combinations in an iterator.
|
||||
///
|
||||
/// See [`.combinations()`](../trait.Itertools.html#method.combinations) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct Combinations<I: Iterator> {
|
||||
indices: Vec<usize>,
|
||||
pool: LazyBuffer<I>,
|
||||
first: bool,
|
||||
}
|
||||
|
||||
impl<I> Clone for Combinations<I>
|
||||
where I: Clone + Iterator,
|
||||
I::Item: Clone,
|
||||
{
|
||||
clone_fields!(indices, pool, first);
|
||||
}
|
||||
|
||||
impl<I> fmt::Debug for Combinations<I>
|
||||
where I: Iterator + fmt::Debug,
|
||||
I::Item: 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
|
||||
{
|
||||
let mut pool: LazyBuffer<I> = LazyBuffer::new(iter);
|
||||
|
||||
for _ in 0..k {
|
||||
if !pool.get_next() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Combinations {
|
||||
indices: (0..k).collect(),
|
||||
pool,
|
||||
first: true,
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for Combinations<I>
|
||||
where I: Iterator,
|
||||
I::Item: Clone
|
||||
{
|
||||
type Item = Vec<I::Item>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.first {
|
||||
if self.pool.is_done() {
|
||||
return None;
|
||||
}
|
||||
self.first = false;
|
||||
} else if self.indices.len() == 0 {
|
||||
return None;
|
||||
} else {
|
||||
// Scan from the end, looking for an index to increment
|
||||
let mut i: usize = self.indices.len() - 1;
|
||||
|
||||
// Check if we need to consume more from the iterator
|
||||
if self.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() {
|
||||
if i > 0 {
|
||||
i -= 1;
|
||||
} else {
|
||||
// Reached the last combination
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Create result vector based on the indices
|
||||
Some(self.indices.iter().map(|i| self.pool[*i].clone()).collect())
|
||||
}
|
||||
}
|
107
vendor/itertools/src/combinations_with_replacement.rs
vendored
Normal file
107
vendor/itertools/src/combinations_with_replacement.rs
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
use std::fmt;
|
||||
|
||||
use super::lazy_buffer::LazyBuffer;
|
||||
|
||||
/// An iterator to iterate through all the `n`-length combinations in an iterator, with replacement.
|
||||
///
|
||||
/// See [`.combinations_with_replacement()`](../trait.Itertools.html#method.combinations_with_replacement) for more information.
|
||||
#[derive(Clone)]
|
||||
pub struct CombinationsWithReplacement<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
{
|
||||
k: usize,
|
||||
indices: Vec<usize>,
|
||||
// The current known max index value. This increases as pool grows.
|
||||
max_index: usize,
|
||||
pool: LazyBuffer<I>,
|
||||
first: bool,
|
||||
}
|
||||
|
||||
impl<I> fmt::Debug for CombinationsWithReplacement<I>
|
||||
where
|
||||
I: Iterator + fmt::Debug,
|
||||
I::Item: fmt::Debug + Clone,
|
||||
{
|
||||
debug_fmt_fields!(Combinations, k, indices, max_index, pool, first);
|
||||
}
|
||||
|
||||
impl<I> CombinationsWithReplacement<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
{
|
||||
/// Map the current mask over the pool to get an output combination
|
||||
fn current(&self) -> Vec<I::Item> {
|
||||
self.indices.iter().map(|i| self.pool[*i].clone()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `CombinationsWithReplacement` from a clonable iterator.
|
||||
pub fn combinations_with_replacement<I>(iter: I, k: usize) -> CombinationsWithReplacement<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
{
|
||||
let indices: Vec<usize> = vec![0; k];
|
||||
let pool: LazyBuffer<I> = LazyBuffer::new(iter);
|
||||
|
||||
CombinationsWithReplacement {
|
||||
k,
|
||||
indices,
|
||||
max_index: 0,
|
||||
pool,
|
||||
first: true,
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for CombinationsWithReplacement<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
{
|
||||
type Item = Vec<I::Item>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// If this is the first iteration, return early
|
||||
if self.first {
|
||||
// In empty edge cases, stop iterating immediately
|
||||
return if self.k != 0 && !self.pool.get_next() {
|
||||
None
|
||||
// Otherwise, yield the initial state
|
||||
} else {
|
||||
self.first = false;
|
||||
Some(self.current())
|
||||
};
|
||||
}
|
||||
|
||||
// Check if we need to consume more from the iterator
|
||||
// This will run while we increment our first index digit
|
||||
if self.pool.get_next() {
|
||||
self.max_index = self.pool.len() - 1;
|
||||
}
|
||||
|
||||
// Work out where we need to update our indices
|
||||
let mut increment: Option<(usize, usize)> = None;
|
||||
for (i, indices_int) in self.indices.iter().enumerate().rev() {
|
||||
if indices_int < &self.max_index {
|
||||
increment = Some((i, indices_int + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match increment {
|
||||
// If we can update the indices further
|
||||
Some((increment_from, increment_value)) => {
|
||||
// We need to update the rightmost non-max value
|
||||
// and all those to the right
|
||||
for indices_index in increment_from..self.indices.len() {
|
||||
self.indices[indices_index] = increment_value
|
||||
}
|
||||
Some(self.current())
|
||||
}
|
||||
// Otherwise, we're done
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
22
vendor/itertools/src/concat_impl.rs
vendored
Normal file
22
vendor/itertools/src/concat_impl.rs
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
use crate::Itertools;
|
||||
|
||||
/// Combine all an iterator's elements into one element by using `Extend`.
|
||||
///
|
||||
/// `IntoIterator`-enabled version of `.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
|
||||
/// `I::Item` is returned.
|
||||
///
|
||||
/// ```rust
|
||||
/// use itertools::concat;
|
||||
///
|
||||
/// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]];
|
||||
/// assert_eq!(concat(input), vec![1, 2, 3, 4, 5, 6]);
|
||||
/// ```
|
||||
pub fn concat<I>(iterable: I) -> I::Item
|
||||
where I: IntoIterator,
|
||||
I::Item: Extend<<<I as IntoIterator>::Item as IntoIterator>::Item> + IntoIterator + Default
|
||||
{
|
||||
iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_else(|| <_>::default())
|
||||
}
|
64
vendor/itertools/src/cons_tuples_impl.rs
vendored
Normal file
64
vendor/itertools/src/cons_tuples_impl.rs
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
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, )))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl<X, Iter, $($B),*> DoubleEndedIterator for ConsTuples<Iter, (($($B,)*), X)>
|
||||
where Iter: DoubleEndedIterator<Item = (($($B,)*), X)>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, ))
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
);
|
||||
|
||||
impl_cons_iter!(A, B, C, D, E, F, G, H,);
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
/// 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, J>
|
||||
where I: Iterator<Item=J>
|
||||
{
|
||||
ConsTuples { iter: iterable.into_iter() }
|
||||
}
|
61
vendor/itertools/src/diff.rs
vendored
Normal file
61
vendor/itertools/src/diff.rs
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
|
||||
//! elements' iterator to be `Clone`.
|
||||
//!
|
||||
//! - [**Diff**](./enum.Diff.html) (produced by the [**diff_with**](./fn.diff_with.html) function)
|
||||
//! describes the difference between two non-`Clone` iterators `I` and `J` after breaking ASAP from
|
||||
//! a lock-step comparison.
|
||||
|
||||
use crate::free::put_back;
|
||||
use crate::structs::PutBack;
|
||||
|
||||
/// A type returned by the [`diff_with`](./fn.diff_with.html) function.
|
||||
///
|
||||
/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some
|
||||
/// iterator `J`.
|
||||
pub enum Diff<I, J>
|
||||
where I: Iterator,
|
||||
J: Iterator
|
||||
{
|
||||
/// The index of the first non-matching element along with both iterator's remaining elements
|
||||
/// starting with the first mis-match.
|
||||
FirstMismatch(usize, PutBack<I>, PutBack<J>),
|
||||
/// The total number of elements that were in `J` along with the remaining elements of `I`.
|
||||
Shorter(usize, PutBack<I>),
|
||||
/// The total number of elements that were in `I` along with the remaining elements of `J`.
|
||||
Longer(usize, PutBack<J>),
|
||||
}
|
||||
|
||||
/// Compares every element yielded by both `i` and `j` with the given function in lock-step and
|
||||
/// returns a `Diff` which describes how `j` differs from `i`.
|
||||
///
|
||||
/// If the number of elements yielded by `j` is less than the number of elements yielded by `i`,
|
||||
/// the number of `j` elements yielded will be returned along with `i`'s remaining elements as
|
||||
/// `Diff::Shorter`.
|
||||
///
|
||||
/// If the two elements of a step differ, the index of those elements along with the remaining
|
||||
/// elements of both `i` and `j` are returned as `Diff::FirstMismatch`.
|
||||
///
|
||||
/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with
|
||||
/// the remaining `j` elements will be returned as `Diff::Longer`.
|
||||
pub fn diff_with<I, J, F>(i: I, j: J, is_equal: F)
|
||||
-> Option<Diff<I::IntoIter, J::IntoIter>>
|
||||
where I: IntoIterator,
|
||||
J: IntoIterator,
|
||||
F: Fn(&I::Item, &J::Item) -> bool
|
||||
{
|
||||
let mut i = i.into_iter();
|
||||
let mut j = j.into_iter();
|
||||
let mut idx = 0;
|
||||
while let Some(i_elem) = i.next() {
|
||||
match j.next() {
|
||||
None => return Some(Diff::Shorter(idx, put_back(i).with_value(i_elem))),
|
||||
Some(j_elem) => if !is_equal(&i_elem, &j_elem) {
|
||||
let remaining_i = put_back(i).with_value(i_elem);
|
||||
let remaining_j = put_back(j).with_value(j_elem);
|
||||
return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j));
|
||||
},
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
j.next().map(|j_elem| Diff::Longer(idx, put_back(j).with_value(j_elem)))
|
||||
}
|
190
vendor/itertools/src/either_or_both.rs
vendored
Normal file
190
vendor/itertools/src/either_or_both.rs
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
use crate::EitherOrBoth::*;
|
||||
|
||||
use either::Either;
|
||||
|
||||
/// Value that either holds a single A or B, or both.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum EitherOrBoth<A, B> {
|
||||
/// Both values are present.
|
||||
Both(A, B),
|
||||
/// Only the left value of type `A` is present.
|
||||
Left(A),
|
||||
/// Only the right value of type `B` is present.
|
||||
Right(B),
|
||||
}
|
||||
|
||||
impl<A, B> EitherOrBoth<A, B> {
|
||||
/// If `Left`, or `Both`, return true, otherwise, return false.
|
||||
pub fn has_left(&self) -> bool {
|
||||
self.as_ref().left().is_some()
|
||||
}
|
||||
|
||||
/// If `Right`, or `Both`, return true, otherwise, return false.
|
||||
pub fn has_right(&self) -> bool {
|
||||
self.as_ref().right().is_some()
|
||||
}
|
||||
|
||||
/// If Left, return true otherwise, return false.
|
||||
/// Exclusive version of [`has_left`].
|
||||
pub fn is_left(&self) -> bool {
|
||||
match *self {
|
||||
Left(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// If Right, return true otherwise, return false.
|
||||
/// Exclusive version of [`has_right`].
|
||||
pub fn is_right(&self) -> bool {
|
||||
match *self {
|
||||
Right(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// If Right, return true otherwise, return false.
|
||||
/// Equivalent to `self.as_ref().both().is_some()`.
|
||||
pub fn is_both(&self) -> bool {
|
||||
self.as_ref().both().is_some()
|
||||
}
|
||||
|
||||
/// If `Left`, or `Both`, return `Some` with the left value, otherwise, return `None`.
|
||||
pub fn left(self) -> Option<A> {
|
||||
match self {
|
||||
Left(left) | Both(left, _) => Some(left),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// If `Right`, or `Both`, return `Some` with the right value, otherwise, return `None`.
|
||||
pub fn right(self) -> Option<B> {
|
||||
match self {
|
||||
Right(right) | Both(_, right) => Some(right),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// If Both, return `Some` tuple containing left and right.
|
||||
pub fn both(self) -> Option<(A, B)> {
|
||||
match self {
|
||||
Both(a, b) => Some((a, b)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `&EitherOrBoth<A, B>` to `EitherOrBoth<&A, &B>`.
|
||||
pub fn as_ref(&self) -> EitherOrBoth<&A, &B> {
|
||||
match *self {
|
||||
Left(ref left) => Left(left),
|
||||
Right(ref right) => Right(right),
|
||||
Both(ref left, ref right) => Both(left, right),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `&mut EitherOrBoth<A, B>` to `EitherOrBoth<&mut A, &mut B>`.
|
||||
pub fn as_mut(&mut self) -> EitherOrBoth<&mut A, &mut B> {
|
||||
match *self {
|
||||
Left(ref mut left) => Left(left),
|
||||
Right(ref mut right) => Right(right),
|
||||
Both(ref mut left, ref mut right) => Both(left, right),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `EitherOrBoth<A, B>` to `EitherOrBoth<B, A>`.
|
||||
pub fn flip(self) -> EitherOrBoth<B, A> {
|
||||
match self {
|
||||
Left(a) => Right(a),
|
||||
Right(b) => Left(b),
|
||||
Both(a, b) => Both(b, a),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply the function `f` on the value `a` in `Left(a)` or `Both(a, b)` variants. If it is
|
||||
/// present rewrapping the result in `self`'s original variant.
|
||||
pub fn map_left<F, M>(self, f: F) -> EitherOrBoth<M, B>
|
||||
where
|
||||
F: FnOnce(A) -> M,
|
||||
{
|
||||
match self {
|
||||
Both(a, b) => Both(f(a), b),
|
||||
Left(a) => Left(f(a)),
|
||||
Right(b) => Right(b),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, b)` variants.
|
||||
/// If it is present rewrapping the result in `self`'s original variant.
|
||||
pub fn map_right<F, M>(self, f: F) -> EitherOrBoth<A, M>
|
||||
where
|
||||
F: FnOnce(B) -> M,
|
||||
{
|
||||
match self {
|
||||
Left(a) => Left(a),
|
||||
Right(b) => Right(f(b)),
|
||||
Both(a, b) => Both(a, f(b)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply the functions `f` and `g` on the value `a` and `b` respectively;
|
||||
/// found in `Left(a)`, `Right(b)`, or `Both(a, b)` variants.
|
||||
/// The Result is rewrapped `self`'s original variant.
|
||||
pub fn map_any<F, L, G, R>(self, f: F, g: G) -> EitherOrBoth<L, R>
|
||||
where
|
||||
F: FnOnce(A) -> L,
|
||||
G: FnOnce(B) -> R,
|
||||
{
|
||||
match self {
|
||||
Left(a) => Left(f(a)),
|
||||
Right(b) => Right(g(b)),
|
||||
Both(a, b) => Both(f(a), g(b)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, _)` variants if it is
|
||||
/// present.
|
||||
pub fn left_and_then<F, L>(self, f: F) -> EitherOrBoth<L, B>
|
||||
where
|
||||
F: FnOnce(A) -> EitherOrBoth<L, B>,
|
||||
{
|
||||
match self {
|
||||
Left(a) | Both(a, _) => f(a),
|
||||
Right(b) => Right(b),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply the function `f` on the value `a`
|
||||
/// in `Left(a)` or `Both(a, _)` variants if it is present.
|
||||
pub fn right_and_then<F, R>(self, f: F) -> EitherOrBoth<A, R>
|
||||
where
|
||||
F: FnOnce(B) -> EitherOrBoth<A, R>,
|
||||
{
|
||||
match self {
|
||||
Left(a) => Left(a),
|
||||
Right(b) | Both(_, b) => f(b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> EitherOrBoth<T, T> {
|
||||
/// Return either value of left, right, or the product of `f` applied where `Both` are present.
|
||||
pub fn reduce<F>(self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(T, T) -> T,
|
||||
{
|
||||
match self {
|
||||
Left(a) => a,
|
||||
Right(b) => b,
|
||||
Both(a, b) => f(a, b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> Into<Option<Either<A, B>>> for EitherOrBoth<A, B> {
|
||||
fn into(self) -> Option<Either<A, B>> {
|
||||
match self {
|
||||
EitherOrBoth::Left(l) => Some(Either::Left(l)),
|
||||
EitherOrBoth::Right(r) => Some(Either::Right(r)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
58
vendor/itertools/src/exactly_one_err.rs
vendored
Normal file
58
vendor/itertools/src/exactly_one_err.rs
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
use std::iter::ExactSizeIterator;
|
||||
|
||||
use crate::size_hint;
|
||||
|
||||
/// Iterator returned for the error case of `IterTools::exactly_one()`
|
||||
/// This iterator yields exactly the same elements as the input iterator.
|
||||
///
|
||||
/// During the execution of exactly_one the iterator must be mutated. This wrapper
|
||||
/// effectively "restores" the state of the input iterator when it's handed back.
|
||||
///
|
||||
/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
|
||||
/// use a `Vec`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExactlyOneError<I>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
first_two: (Option<I::Item>, Option<I::Item>),
|
||||
inner: I,
|
||||
}
|
||||
|
||||
impl<I> ExactlyOneError<I>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
/// Creates a new `ExactlyOneErr` iterator.
|
||||
pub(crate) fn new(first_two: (Option<I::Item>, Option<I::Item>), inner: I) -> Self {
|
||||
Self { first_two, inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for ExactlyOneError<I>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.first_two
|
||||
.0
|
||||
.take()
|
||||
.or_else(|| self.first_two.1.take())
|
||||
.or_else(|| self.inner.next())
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let mut additional_len = 0;
|
||||
if self.first_two.0.is_some() {
|
||||
additional_len += 1;
|
||||
}
|
||||
if self.first_two.1.is_some() {
|
||||
additional_len += 1;
|
||||
}
|
||||
size_hint::add_scalar(self.inner.size_hint(), additional_len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}
|
114
vendor/itertools/src/format.rs
vendored
Normal file
114
vendor/itertools/src/format.rs
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
use std::fmt;
|
||||
use std::cell::RefCell;
|
||||
|
||||
/// Format all iterator elements lazily, separated by `sep`.
|
||||
///
|
||||
/// The format value can only be formatted once, after that the iterator is
|
||||
/// exhausted.
|
||||
///
|
||||
/// See [`.format_with()`](../trait.Itertools.html#method.format_with) for more information.
|
||||
#[derive(Clone)]
|
||||
pub struct FormatWith<'a, I, F> {
|
||||
sep: &'a str,
|
||||
/// FormatWith uses interior mutability because Display::fmt takes &self.
|
||||
inner: RefCell<Option<(I, F)>>,
|
||||
}
|
||||
|
||||
/// Format all iterator elements lazily, separated by `sep`.
|
||||
///
|
||||
/// The format value can only be formatted once, after that the iterator is
|
||||
/// exhausted.
|
||||
///
|
||||
/// See [`.format()`](../trait.Itertools.html#method.format)
|
||||
/// for more information.
|
||||
#[derive(Clone)]
|
||||
pub struct Format<'a, I> {
|
||||
sep: &'a str,
|
||||
/// Format uses interior mutability because Display::fmt takes &self.
|
||||
inner: RefCell<Option<I>>,
|
||||
}
|
||||
|
||||
pub fn new_format<'a, I, F>(iter: I, separator: &'a str, f: F) -> FormatWith<'a, I, F>
|
||||
where I: Iterator,
|
||||
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result
|
||||
{
|
||||
FormatWith {
|
||||
sep: separator,
|
||||
inner: RefCell::new(Some((iter, f))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_format_default<'a, I>(iter: I, separator: &'a str) -> Format<'a, I>
|
||||
where I: Iterator,
|
||||
{
|
||||
Format {
|
||||
sep: separator,
|
||||
inner: RefCell::new(Some(iter)),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I, F> fmt::Display for FormatWith<'a, I, F>
|
||||
where I: Iterator,
|
||||
F: FnMut(I::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let (mut iter, mut format) = match self.inner.borrow_mut().take() {
|
||||
Some(t) => t,
|
||||
None => panic!("FormatWith: was already formatted once"),
|
||||
};
|
||||
|
||||
if let Some(fst) = iter.next() {
|
||||
format(fst, &mut |disp: &dyn fmt::Display| disp.fmt(f))?;
|
||||
for elt in iter {
|
||||
if self.sep.len() > 0 {
|
||||
|
||||
f.write_str(self.sep)?;
|
||||
}
|
||||
format(elt, &mut |disp: &dyn fmt::Display| disp.fmt(f))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I> Format<'a, I>
|
||||
where I: Iterator,
|
||||
{
|
||||
fn format<F>(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result
|
||||
where F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result,
|
||||
{
|
||||
let mut iter = match self.inner.borrow_mut().take() {
|
||||
Some(t) => t,
|
||||
None => panic!("Format: was already formatted once"),
|
||||
};
|
||||
|
||||
if let Some(fst) = iter.next() {
|
||||
cb(&fst, f)?;
|
||||
for elt in iter {
|
||||
if self.sep.len() > 0 {
|
||||
f.write_str(self.sep)?;
|
||||
}
|
||||
cb(&elt, f)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_format {
|
||||
($($fmt_trait:ident)*) => {
|
||||
$(
|
||||
impl<'a, I> fmt::$fmt_trait for Format<'a, I>
|
||||
where I: Iterator,
|
||||
I::Item: fmt::$fmt_trait,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f, fmt::$fmt_trait::fmt)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_format!{Display Debug
|
||||
UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer}
|
236
vendor/itertools/src/free.rs
vendored
Normal file
236
vendor/itertools/src/free.rs
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
//! Free functions that create iterator adaptors or call iterator methods.
|
||||
//!
|
||||
//! The benefit of free functions is that they accept any `IntoIterator` as
|
||||
//! argument, so the resulting code may be easier to read.
|
||||
|
||||
#[cfg(feature = "use_std")]
|
||||
use std::fmt::Display;
|
||||
use std::iter::{self, Zip};
|
||||
#[cfg(feature = "use_std")]
|
||||
type VecIntoIter<T> = ::std::vec::IntoIter<T>;
|
||||
|
||||
#[cfg(feature = "use_std")]
|
||||
use crate::Itertools;
|
||||
|
||||
pub use crate::adaptors::{
|
||||
interleave,
|
||||
merge,
|
||||
put_back,
|
||||
};
|
||||
#[cfg(feature = "use_std")]
|
||||
pub use crate::put_back_n_impl::put_back_n;
|
||||
#[cfg(feature = "use_std")]
|
||||
pub use crate::multipeek_impl::multipeek;
|
||||
#[cfg(feature = "use_std")]
|
||||
pub use crate::kmerge_impl::kmerge;
|
||||
pub use crate::zip_eq_impl::zip_eq;
|
||||
pub use crate::merge_join::merge_join_by;
|
||||
#[cfg(feature = "use_std")]
|
||||
pub use crate::rciter_impl::rciter;
|
||||
|
||||
/// Iterate `iterable` with a running index.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `.enumerate()`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::enumerate;
|
||||
///
|
||||
/// for (i, elt) in enumerate(&[1, 2, 3]) {
|
||||
/// /* loop body */
|
||||
/// }
|
||||
/// ```
|
||||
pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
|
||||
where I: IntoIterator
|
||||
{
|
||||
iterable.into_iter().enumerate()
|
||||
}
|
||||
|
||||
/// Iterate `iterable` in reverse.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `.rev()`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::rev;
|
||||
///
|
||||
/// for elt in rev(&[1, 2, 3]) {
|
||||
/// /* loop body */
|
||||
/// }
|
||||
/// ```
|
||||
pub fn rev<I>(iterable: I) -> iter::Rev<I::IntoIter>
|
||||
where I: IntoIterator,
|
||||
I::IntoIter: DoubleEndedIterator
|
||||
{
|
||||
iterable.into_iter().rev()
|
||||
}
|
||||
|
||||
/// Iterate `i` and `j` in lock step.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `i.zip(j)`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::zip;
|
||||
///
|
||||
/// let data = [1, 2, 3, 4, 5];
|
||||
/// for (a, b) in zip(&data, &data[1..]) {
|
||||
/// /* loop body */
|
||||
/// }
|
||||
/// ```
|
||||
pub fn zip<I, J>(i: I, j: J) -> Zip<I::IntoIter, J::IntoIter>
|
||||
where I: IntoIterator,
|
||||
J: IntoIterator
|
||||
{
|
||||
i.into_iter().zip(j)
|
||||
}
|
||||
|
||||
/// Create an iterator that first iterates `i` and then `j`.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `i.chain(j)`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::chain;
|
||||
///
|
||||
/// for elt in chain(&[1, 2, 3], &[4]) {
|
||||
/// /* loop body */
|
||||
/// }
|
||||
/// ```
|
||||
pub fn chain<I, J>(i: I, j: J) -> iter::Chain<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
|
||||
where I: IntoIterator,
|
||||
J: IntoIterator<Item = I::Item>
|
||||
{
|
||||
i.into_iter().chain(j)
|
||||
}
|
||||
|
||||
/// Create an iterator that clones each element from &T to T
|
||||
///
|
||||
/// `IntoIterator` enabled version of `i.cloned()`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::cloned;
|
||||
///
|
||||
/// assert_eq!(cloned(b"abc").next(), Some(b'a'));
|
||||
/// ```
|
||||
pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned<I::IntoIter>
|
||||
where I: IntoIterator<Item=&'a T>,
|
||||
T: Clone,
|
||||
{
|
||||
iterable.into_iter().cloned()
|
||||
}
|
||||
|
||||
/// Perform a fold operation over the iterable.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `i.fold(init, f)`
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::fold;
|
||||
///
|
||||
/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.);
|
||||
/// ```
|
||||
pub fn fold<I, B, F>(iterable: I, init: B, f: F) -> B
|
||||
where I: IntoIterator,
|
||||
F: FnMut(B, I::Item) -> B
|
||||
{
|
||||
iterable.into_iter().fold(init, f)
|
||||
}
|
||||
|
||||
/// Test whether the predicate holds for all elements in the iterable.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `i.all(f)`
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::all;
|
||||
///
|
||||
/// assert!(all(&[1, 2, 3], |elt| *elt > 0));
|
||||
/// ```
|
||||
pub fn all<I, F>(iterable: I, f: F) -> bool
|
||||
where I: IntoIterator,
|
||||
F: FnMut(I::Item) -> bool
|
||||
{
|
||||
iterable.into_iter().all(f)
|
||||
}
|
||||
|
||||
/// Test whether the predicate holds for any elements in the iterable.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `i.any(f)`
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::any;
|
||||
///
|
||||
/// assert!(any(&[0, -1, 2], |elt| *elt > 0));
|
||||
/// ```
|
||||
pub fn any<I, F>(iterable: I, f: F) -> bool
|
||||
where I: IntoIterator,
|
||||
F: FnMut(I::Item) -> bool
|
||||
{
|
||||
iterable.into_iter().any(f)
|
||||
}
|
||||
|
||||
/// Return the maximum value of the iterable.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `i.max()`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::max;
|
||||
///
|
||||
/// assert_eq!(max(0..10), Some(9));
|
||||
/// ```
|
||||
pub fn max<I>(iterable: I) -> Option<I::Item>
|
||||
where I: IntoIterator,
|
||||
I::Item: Ord
|
||||
{
|
||||
iterable.into_iter().max()
|
||||
}
|
||||
|
||||
/// Return the minimum value of the iterable.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `i.min()`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::min;
|
||||
///
|
||||
/// assert_eq!(min(0..10), Some(0));
|
||||
/// ```
|
||||
pub fn min<I>(iterable: I) -> Option<I::Item>
|
||||
where I: IntoIterator,
|
||||
I::Item: Ord
|
||||
{
|
||||
iterable.into_iter().min()
|
||||
}
|
||||
|
||||
|
||||
/// Combine all iterator elements into one String, seperated by `sep`.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `iterable.join(sep)`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::join;
|
||||
///
|
||||
/// assert_eq!(join(&[1, 2, 3], ", "), "1, 2, 3");
|
||||
/// ```
|
||||
#[cfg(feature = "use_std")]
|
||||
pub fn join<I>(iterable: I, sep: &str) -> String
|
||||
where I: IntoIterator,
|
||||
I::Item: Display
|
||||
{
|
||||
iterable.into_iter().join(sep)
|
||||
}
|
||||
|
||||
/// Sort all iterator elements into a new iterator in ascending order.
|
||||
///
|
||||
/// `IntoIterator` enabled version of [`iterable.sorted()`][1].
|
||||
///
|
||||
/// [1]: trait.Itertools.html#method.sorted
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::sorted;
|
||||
/// use itertools::assert_equal;
|
||||
///
|
||||
/// assert_equal(sorted("rust".chars()), "rstu".chars());
|
||||
/// ```
|
||||
#[cfg(feature = "use_std")]
|
||||
pub fn sorted<I>(iterable: I) -> VecIntoIter<I::Item>
|
||||
where I: IntoIterator,
|
||||
I::Item: Ord
|
||||
{
|
||||
iterable.into_iter().sorted()
|
||||
}
|
||||
|
22
vendor/itertools/src/group_map.rs
vendored
Normal file
22
vendor/itertools/src/group_map.rs
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
#![cfg(feature = "use_std")]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
use std::iter::Iterator;
|
||||
|
||||
/// Return a `HashMap` of keys mapped to a list of their corresponding values.
|
||||
///
|
||||
/// See [`.into_group_map()`](../trait.Itertools.html#method.into_group_map)
|
||||
/// for more information.
|
||||
pub fn into_group_map<I, K, V>(iter: I) -> HashMap<K, Vec<V>>
|
||||
where I: Iterator<Item=(K, V)>,
|
||||
K: Hash + Eq,
|
||||
{
|
||||
let mut lookup = HashMap::new();
|
||||
|
||||
for (key, val) in iter {
|
||||
lookup.entry(key).or_insert(Vec::new()).push(val);
|
||||
}
|
||||
|
||||
lookup
|
||||
}
|
571
vendor/itertools/src/groupbylazy.rs
vendored
Normal file
571
vendor/itertools/src/groupbylazy.rs
vendored
Normal file
@ -0,0 +1,571 @@
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::vec;
|
||||
|
||||
/// A trait to unify FnMut for GroupBy with the chunk key in IntoChunks
|
||||
trait KeyFunction<A> {
|
||||
type Key;
|
||||
fn call_mut(&mut self, arg: A) -> Self::Key;
|
||||
}
|
||||
|
||||
impl<'a, A, K, F: ?Sized> KeyFunction<A> for F
|
||||
where F: FnMut(A) -> K
|
||||
{
|
||||
type Key = K;
|
||||
#[inline]
|
||||
fn call_mut(&mut self, arg: A) -> Self::Key {
|
||||
(*self)(arg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// ChunkIndex acts like the grouping key function for IntoChunks
|
||||
#[derive(Debug)]
|
||||
struct ChunkIndex {
|
||||
size: usize,
|
||||
index: usize,
|
||||
key: usize,
|
||||
}
|
||||
|
||||
impl ChunkIndex {
|
||||
#[inline(always)]
|
||||
fn new(size: usize) -> Self {
|
||||
ChunkIndex {
|
||||
size,
|
||||
index: 0,
|
||||
key: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A> KeyFunction<A> for ChunkIndex {
|
||||
type Key = usize;
|
||||
#[inline(always)]
|
||||
fn call_mut(&mut self, _arg: A) -> Self::Key {
|
||||
if self.index == self.size {
|
||||
self.key += 1;
|
||||
self.index = 0;
|
||||
}
|
||||
self.index += 1;
|
||||
self.key
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct GroupInner<K, I, F>
|
||||
where I: Iterator
|
||||
{
|
||||
key: F,
|
||||
iter: I,
|
||||
current_key: Option<K>,
|
||||
current_elt: Option<I::Item>,
|
||||
/// flag set if iterator is exhausted
|
||||
done: bool,
|
||||
/// Index of group we are currently buffering or visiting
|
||||
top_group: usize,
|
||||
/// Least index for which we still have elements buffered
|
||||
oldest_buffered_group: usize,
|
||||
/// Group index for `buffer[0]` -- the slots
|
||||
/// bottom_group..oldest_buffered_group are unused and will be erased when
|
||||
/// that range is large enough.
|
||||
bottom_group: usize,
|
||||
/// Buffered groups, from `bottom_group` (index 0) to `top_group`.
|
||||
buffer: Vec<vec::IntoIter<I::Item>>,
|
||||
/// index of last group iter that was dropped, usize::MAX == none
|
||||
dropped_group: usize,
|
||||
}
|
||||
|
||||
impl<K, I, F> GroupInner<K, I, F>
|
||||
where I: Iterator,
|
||||
F: for<'a> KeyFunction<&'a I::Item, Key=K>,
|
||||
K: PartialEq,
|
||||
{
|
||||
/// `client`: Index of group that requests next element
|
||||
#[inline(always)]
|
||||
fn step(&mut self, client: usize) -> Option<I::Item> {
|
||||
/*
|
||||
println!("client={}, bottom_group={}, oldest_buffered_group={}, top_group={}, buffers=[{}]",
|
||||
client, self.bottom_group, self.oldest_buffered_group,
|
||||
self.top_group,
|
||||
self.buffer.iter().map(|elt| elt.len()).format(", "));
|
||||
*/
|
||||
if client < self.oldest_buffered_group {
|
||||
None
|
||||
} else if client < self.top_group ||
|
||||
(client == self.top_group &&
|
||||
self.buffer.len() > self.top_group - self.bottom_group)
|
||||
{
|
||||
self.lookup_buffer(client)
|
||||
} else if self.done {
|
||||
None
|
||||
} else if self.top_group == client {
|
||||
self.step_current()
|
||||
} else {
|
||||
self.step_buffering(client)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn lookup_buffer(&mut self, client: usize) -> Option<I::Item> {
|
||||
// if `bufidx` doesn't exist in self.buffer, it might be empty
|
||||
let bufidx = client - self.bottom_group;
|
||||
if client < self.oldest_buffered_group {
|
||||
return None;
|
||||
}
|
||||
let elt = self.buffer.get_mut(bufidx).and_then(|queue| queue.next());
|
||||
if elt.is_none() && client == self.oldest_buffered_group {
|
||||
// FIXME: VecDeque is unfortunately not zero allocation when empty,
|
||||
// so we do this job manually.
|
||||
// `bottom_group..oldest_buffered_group` is unused, and if it's large enough, erase it.
|
||||
self.oldest_buffered_group += 1;
|
||||
// skip forward further empty queues too
|
||||
while self.buffer.get(self.oldest_buffered_group - self.bottom_group)
|
||||
.map_or(false, |buf| buf.len() == 0)
|
||||
{
|
||||
self.oldest_buffered_group += 1;
|
||||
}
|
||||
|
||||
let nclear = self.oldest_buffered_group - self.bottom_group;
|
||||
if nclear > 0 && nclear >= self.buffer.len() / 2 {
|
||||
let mut i = 0;
|
||||
self.buffer.retain(|buf| {
|
||||
i += 1;
|
||||
debug_assert!(buf.len() == 0 || i > nclear);
|
||||
i > nclear
|
||||
});
|
||||
self.bottom_group = self.oldest_buffered_group;
|
||||
}
|
||||
}
|
||||
elt
|
||||
}
|
||||
|
||||
/// Take the next element from the iterator, and set the done
|
||||
/// flag if exhausted. Must not be called after done.
|
||||
#[inline(always)]
|
||||
fn next_element(&mut self) -> Option<I::Item> {
|
||||
debug_assert!(!self.done);
|
||||
match self.iter.next() {
|
||||
None => { self.done = true; None }
|
||||
otherwise => otherwise,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[inline(never)]
|
||||
fn step_buffering(&mut self, client: usize) -> Option<I::Item> {
|
||||
// requested a later group -- walk through the current group up to
|
||||
// the requested group index, and buffer the elements (unless
|
||||
// the group is marked as dropped).
|
||||
// Because the `Groups` iterator is always the first to request
|
||||
// each group index, client is the next index efter top_group.
|
||||
debug_assert!(self.top_group + 1 == client);
|
||||
let mut group = Vec::new();
|
||||
|
||||
if let Some(elt) = self.current_elt.take() {
|
||||
if self.top_group != self.dropped_group {
|
||||
group.push(elt);
|
||||
}
|
||||
}
|
||||
let mut first_elt = None; // first element of the next group
|
||||
|
||||
while let Some(elt) = self.next_element() {
|
||||
let key = self.key.call_mut(&elt);
|
||||
match self.current_key.take() {
|
||||
None => {}
|
||||
Some(old_key) => if old_key != key {
|
||||
self.current_key = Some(key);
|
||||
first_elt = Some(elt);
|
||||
break;
|
||||
},
|
||||
}
|
||||
self.current_key = Some(key);
|
||||
if self.top_group != self.dropped_group {
|
||||
group.push(elt);
|
||||
}
|
||||
}
|
||||
|
||||
if self.top_group != self.dropped_group {
|
||||
self.push_next_group(group);
|
||||
}
|
||||
if first_elt.is_some() {
|
||||
self.top_group += 1;
|
||||
debug_assert!(self.top_group == client);
|
||||
}
|
||||
first_elt
|
||||
}
|
||||
|
||||
fn push_next_group(&mut self, group: Vec<I::Item>) {
|
||||
// When we add a new buffered group, fill up slots between oldest_buffered_group and top_group
|
||||
while self.top_group - self.bottom_group > self.buffer.len() {
|
||||
if self.buffer.is_empty() {
|
||||
self.bottom_group += 1;
|
||||
self.oldest_buffered_group += 1;
|
||||
} else {
|
||||
self.buffer.push(Vec::new().into_iter());
|
||||
}
|
||||
}
|
||||
self.buffer.push(group.into_iter());
|
||||
debug_assert!(self.top_group + 1 - self.bottom_group == self.buffer.len());
|
||||
}
|
||||
|
||||
/// This is the immediate case, where we use no buffering
|
||||
#[inline]
|
||||
fn step_current(&mut self) -> Option<I::Item> {
|
||||
debug_assert!(!self.done);
|
||||
if let elt @ Some(..) = self.current_elt.take() {
|
||||
return elt;
|
||||
}
|
||||
match self.next_element() {
|
||||
None => None,
|
||||
Some(elt) => {
|
||||
let key = self.key.call_mut(&elt);
|
||||
match self.current_key.take() {
|
||||
None => {}
|
||||
Some(old_key) => if old_key != key {
|
||||
self.current_key = Some(key);
|
||||
self.current_elt = Some(elt);
|
||||
self.top_group += 1;
|
||||
return None;
|
||||
},
|
||||
}
|
||||
self.current_key = Some(key);
|
||||
Some(elt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Request the just started groups' key.
|
||||
///
|
||||
/// `client`: Index of group
|
||||
///
|
||||
/// **Panics** if no group key is available.
|
||||
fn group_key(&mut self, client: usize) -> K {
|
||||
// This can only be called after we have just returned the first
|
||||
// element of a group.
|
||||
// Perform this by simply buffering one more element, grabbing the
|
||||
// next key.
|
||||
debug_assert!(!self.done);
|
||||
debug_assert!(client == self.top_group);
|
||||
debug_assert!(self.current_key.is_some());
|
||||
debug_assert!(self.current_elt.is_none());
|
||||
let old_key = self.current_key.take().unwrap();
|
||||
if let Some(elt) = self.next_element() {
|
||||
let key = self.key.call_mut(&elt);
|
||||
if old_key != key {
|
||||
self.top_group += 1;
|
||||
}
|
||||
self.current_key = Some(key);
|
||||
self.current_elt = Some(elt);
|
||||
}
|
||||
old_key
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, I, F> GroupInner<K, I, F>
|
||||
where I: Iterator,
|
||||
{
|
||||
/// Called when a group is dropped
|
||||
fn drop_group(&mut self, client: usize) {
|
||||
// It's only useful to track the maximal index
|
||||
if self.dropped_group == !0 || client > self.dropped_group {
|
||||
self.dropped_group = client;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `GroupBy` is the storage for the lazy grouping operation.
|
||||
///
|
||||
/// If the groups are consumed in their original order, or if each
|
||||
/// group is dropped without keeping it around, then `GroupBy` uses
|
||||
/// no allocations. It needs allocations only if several group iterators
|
||||
/// are alive at the same time.
|
||||
///
|
||||
/// This type implements `IntoIterator` (it is **not** an iterator
|
||||
/// itself), because the group iterators need to borrow from this
|
||||
/// value. It should be stored in a local variable or temporary and
|
||||
/// iterated.
|
||||
///
|
||||
/// See [`.group_by()`](../trait.Itertools.html#method.group_by) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct GroupBy<K, I, F>
|
||||
where I: Iterator,
|
||||
{
|
||||
inner: RefCell<GroupInner<K, I, F>>,
|
||||
// the group iterator's current index. Keep this in the main value
|
||||
// so that simultaneous iterators all use the same state.
|
||||
index: Cell<usize>,
|
||||
}
|
||||
|
||||
/// Create a new
|
||||
pub fn new<K, J, F>(iter: J, f: F) -> GroupBy<K, J::IntoIter, F>
|
||||
where J: IntoIterator,
|
||||
F: FnMut(&J::Item) -> K,
|
||||
{
|
||||
GroupBy {
|
||||
inner: RefCell::new(GroupInner {
|
||||
key: f,
|
||||
iter: iter.into_iter(),
|
||||
current_key: None,
|
||||
current_elt: None,
|
||||
done: false,
|
||||
top_group: 0,
|
||||
oldest_buffered_group: 0,
|
||||
bottom_group: 0,
|
||||
buffer: Vec::new(),
|
||||
dropped_group: !0,
|
||||
}),
|
||||
index: Cell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, I, F> GroupBy<K, I, F>
|
||||
where I: Iterator,
|
||||
{
|
||||
/// `client`: Index of group that requests next element
|
||||
fn step(&self, client: usize) -> Option<I::Item>
|
||||
where F: FnMut(&I::Item) -> K,
|
||||
K: PartialEq,
|
||||
{
|
||||
self.inner.borrow_mut().step(client)
|
||||
}
|
||||
|
||||
/// `client`: Index of group
|
||||
fn drop_group(&self, client: usize) {
|
||||
self.inner.borrow_mut().drop_group(client)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, I, F> IntoIterator for &'a GroupBy<K, I, F>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
F: FnMut(&I::Item) -> K,
|
||||
K: PartialEq
|
||||
{
|
||||
type Item = (K, Group<'a, K, I, F>);
|
||||
type IntoIter = Groups<'a, K, I, F>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Groups { parent: self }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// An iterator that yields the Group iterators.
|
||||
///
|
||||
/// Iterator element type is `(K, Group)`:
|
||||
/// the group's key `K` and the group's iterator.
|
||||
///
|
||||
/// See [`.group_by()`](../trait.Itertools.html#method.group_by) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct Groups<'a, K: 'a, I: 'a, F: 'a>
|
||||
where I: Iterator,
|
||||
I::Item: 'a
|
||||
{
|
||||
parent: &'a GroupBy<K, I, F>,
|
||||
}
|
||||
|
||||
impl<'a, K, I, F> Iterator for Groups<'a, K, I, F>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
F: FnMut(&I::Item) -> K,
|
||||
K: PartialEq
|
||||
{
|
||||
type Item = (K, Group<'a, K, I, F>);
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let index = self.parent.index.get();
|
||||
self.parent.index.set(index + 1);
|
||||
let inner = &mut *self.parent.inner.borrow_mut();
|
||||
inner.step(index).map(|elt| {
|
||||
let key = inner.group_key(index);
|
||||
(key, Group {
|
||||
parent: self.parent,
|
||||
index,
|
||||
first: Some(elt),
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator for the elements in a single group.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
pub struct Group<'a, K: 'a, I: 'a, F: 'a>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
{
|
||||
parent: &'a GroupBy<K, I, F>,
|
||||
index: usize,
|
||||
first: Option<I::Item>,
|
||||
}
|
||||
|
||||
impl<'a, K, I, F> Drop for Group<'a, K, I, F>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.parent.drop_group(self.index);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, I, F> Iterator for Group<'a, K, I, F>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
F: FnMut(&I::Item) -> K,
|
||||
K: PartialEq,
|
||||
{
|
||||
type Item = I::Item;
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let elt @ Some(..) = self.first.take() {
|
||||
return elt;
|
||||
}
|
||||
self.parent.step(self.index)
|
||||
}
|
||||
}
|
||||
|
||||
///// IntoChunks /////
|
||||
|
||||
/// Create a new
|
||||
pub fn new_chunks<J>(iter: J, size: usize) -> IntoChunks<J::IntoIter>
|
||||
where J: IntoIterator,
|
||||
{
|
||||
IntoChunks {
|
||||
inner: RefCell::new(GroupInner {
|
||||
key: ChunkIndex::new(size),
|
||||
iter: iter.into_iter(),
|
||||
current_key: None,
|
||||
current_elt: None,
|
||||
done: false,
|
||||
top_group: 0,
|
||||
oldest_buffered_group: 0,
|
||||
bottom_group: 0,
|
||||
buffer: Vec::new(),
|
||||
dropped_group: !0,
|
||||
}),
|
||||
index: Cell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// `ChunkLazy` is the storage for a lazy chunking operation.
|
||||
///
|
||||
/// `IntoChunks` behaves just like `GroupBy`: it is iterable, and
|
||||
/// it only buffers if several chunk iterators are alive at the same time.
|
||||
///
|
||||
/// This type implements `IntoIterator` (it is **not** an iterator
|
||||
/// itself), because the chunk iterators need to borrow from this
|
||||
/// value. It should be stored in a local variable or temporary and
|
||||
/// iterated.
|
||||
///
|
||||
/// Iterator element type is `Chunk`, each chunk's iterator.
|
||||
///
|
||||
/// See [`.chunks()`](../trait.Itertools.html#method.chunks) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct IntoChunks<I>
|
||||
where I: Iterator,
|
||||
{
|
||||
inner: RefCell<GroupInner<usize, I, ChunkIndex>>,
|
||||
// the chunk iterator's current index. Keep this in the main value
|
||||
// so that simultaneous iterators all use the same state.
|
||||
index: Cell<usize>,
|
||||
}
|
||||
|
||||
|
||||
impl<I> IntoChunks<I>
|
||||
where I: Iterator,
|
||||
{
|
||||
/// `client`: Index of chunk that requests next element
|
||||
fn step(&self, client: usize) -> Option<I::Item> {
|
||||
self.inner.borrow_mut().step(client)
|
||||
}
|
||||
|
||||
/// `client`: Index of chunk
|
||||
fn drop_group(&self, client: usize) {
|
||||
self.inner.borrow_mut().drop_group(client)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I> IntoIterator for &'a IntoChunks<I>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
{
|
||||
type Item = Chunk<'a, I>;
|
||||
type IntoIter = Chunks<'a, I>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Chunks {
|
||||
parent: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// An iterator that yields the Chunk iterators.
|
||||
///
|
||||
/// Iterator element type is `Chunk`.
|
||||
///
|
||||
/// See [`.chunks()`](../trait.Itertools.html#method.chunks) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct Chunks<'a, I: 'a>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
{
|
||||
parent: &'a IntoChunks<I>,
|
||||
}
|
||||
|
||||
impl<'a, I> Iterator for Chunks<'a, I>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
{
|
||||
type Item = Chunk<'a, I>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let index = self.parent.index.get();
|
||||
self.parent.index.set(index + 1);
|
||||
let inner = &mut *self.parent.inner.borrow_mut();
|
||||
inner.step(index).map(|elt| {
|
||||
Chunk {
|
||||
parent: self.parent,
|
||||
index,
|
||||
first: Some(elt),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator for the elements in a single chunk.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
pub struct Chunk<'a, I: 'a>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
{
|
||||
parent: &'a IntoChunks<I>,
|
||||
index: usize,
|
||||
first: Option<I::Item>,
|
||||
}
|
||||
|
||||
impl<'a, I> Drop for Chunk<'a, I>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.parent.drop_group(self.index);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I> Iterator for Chunk<'a, I>
|
||||
where I: Iterator,
|
||||
I::Item: 'a,
|
||||
{
|
||||
type Item = I::Item;
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let elt @ Some(..) = self.first.take() {
|
||||
return elt;
|
||||
}
|
||||
self.parent.step(self.index)
|
||||
}
|
||||
}
|
24
vendor/itertools/src/impl_macros.rs
vendored
Normal file
24
vendor/itertools/src/impl_macros.rs
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
//!
|
||||
//! Implementation's internal macros
|
||||
|
||||
macro_rules! debug_fmt_fields {
|
||||
($tyname:ident, $($($field:ident).+),*) => {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
f.debug_struct(stringify!($tyname))
|
||||
$(
|
||||
.field(stringify!($($field).+), &self.$($field).+)
|
||||
)*
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! clone_fields {
|
||||
($($field:ident),*) => {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
$($field: self.$field.clone(),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
79
vendor/itertools/src/intersperse.rs
vendored
Normal file
79
vendor/itertools/src/intersperse.rs
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
use std::iter::Fuse;
|
||||
use super::size_hint;
|
||||
|
||||
#[derive(Clone)]
|
||||
/// An iterator adaptor to insert a particular value
|
||||
/// between each element of the adapted iterator.
|
||||
///
|
||||
/// Iterator element type is `I::Item`
|
||||
///
|
||||
/// This iterator is *fused*.
|
||||
///
|
||||
/// See [`.intersperse()`](../trait.Itertools.html#method.intersperse) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
#[derive(Debug)]
|
||||
pub struct Intersperse<I>
|
||||
where I: Iterator
|
||||
{
|
||||
element: I::Item,
|
||||
iter: Fuse<I>,
|
||||
peek: Option<I::Item>,
|
||||
}
|
||||
|
||||
/// Create a new Intersperse iterator
|
||||
pub fn intersperse<I>(iter: I, elt: I::Item) -> Intersperse<I>
|
||||
where I: Iterator
|
||||
{
|
||||
let mut iter = iter.fuse();
|
||||
Intersperse {
|
||||
peek: iter.next(),
|
||||
iter,
|
||||
element: elt,
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for Intersperse<I>
|
||||
where I: Iterator,
|
||||
I::Item: Clone
|
||||
{
|
||||
type Item = I::Item;
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
if self.peek.is_some() {
|
||||
self.peek.take()
|
||||
} else {
|
||||
self.peek = self.iter.next();
|
||||
if self.peek.is_some() {
|
||||
Some(self.element.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
// 2 * SH + { 1 or 0 }
|
||||
let has_peek = self.peek.is_some() as usize;
|
||||
let sh = self.iter.size_hint();
|
||||
size_hint::add_scalar(size_hint::add(sh, sh), has_peek)
|
||||
}
|
||||
|
||||
fn fold<B, F>(mut self, init: B, mut f: F) -> B where
|
||||
Self: Sized, F: FnMut(B, Self::Item) -> B,
|
||||
{
|
||||
let mut accum = init;
|
||||
|
||||
if let Some(x) = self.peek.take() {
|
||||
accum = f(accum, x);
|
||||
}
|
||||
|
||||
let element = &self.element;
|
||||
|
||||
self.iter.fold(accum,
|
||||
|accum, x| {
|
||||
let accum = f(accum, element.clone());
|
||||
let accum = f(accum, x);
|
||||
accum
|
||||
})
|
||||
}
|
||||
}
|
216
vendor/itertools/src/kmerge_impl.rs
vendored
Normal file
216
vendor/itertools/src/kmerge_impl.rs
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
use crate::size_hint;
|
||||
use crate::Itertools;
|
||||
|
||||
use std::mem::replace;
|
||||
use std::fmt;
|
||||
|
||||
/// Head element and Tail iterator pair
|
||||
///
|
||||
/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
|
||||
/// first items (which are guaranteed to exist).
|
||||
///
|
||||
/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
|
||||
/// `KMerge` into a min-heap.
|
||||
#[derive(Debug)]
|
||||
struct HeadTail<I>
|
||||
where I: Iterator
|
||||
{
|
||||
head: I::Item,
|
||||
tail: I,
|
||||
}
|
||||
|
||||
impl<I> HeadTail<I>
|
||||
where I: Iterator
|
||||
{
|
||||
/// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
|
||||
fn new(mut it: I) -> Option<HeadTail<I>> {
|
||||
let head = it.next();
|
||||
head.map(|h| {
|
||||
HeadTail {
|
||||
head: h,
|
||||
tail: it,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the next element and update `head`, returning the old head in `Some`.
|
||||
///
|
||||
/// Returns `None` when the tail is exhausted (only `head` then remains).
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
if let Some(next) = self.tail.next() {
|
||||
Some(replace(&mut self.head, next))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Hints at the size of the sequence, same as the `Iterator` method.
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
size_hint::add_scalar(self.tail.size_hint(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Clone for HeadTail<I>
|
||||
where I: Iterator + Clone,
|
||||
I::Item: Clone
|
||||
{
|
||||
clone_fields!(head, tail);
|
||||
}
|
||||
|
||||
/// Make `data` a heap (min-heap w.r.t the sorting).
|
||||
fn heapify<T, S>(data: &mut [T], mut less_than: S)
|
||||
where S: FnMut(&T, &T) -> bool
|
||||
{
|
||||
for i in (0..data.len() / 2).rev() {
|
||||
sift_down(data, i, &mut less_than);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
|
||||
fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
|
||||
where S: FnMut(&T, &T) -> bool
|
||||
{
|
||||
debug_assert!(index <= heap.len());
|
||||
let mut pos = index;
|
||||
let mut child = 2 * pos + 1;
|
||||
// the `pos` conditional is to avoid a bounds check
|
||||
while pos < heap.len() && child < heap.len() {
|
||||
let right = child + 1;
|
||||
|
||||
// pick the smaller of the two children
|
||||
if right < heap.len() && less_than(&heap[right], &heap[child]) {
|
||||
child = right;
|
||||
}
|
||||
|
||||
// sift down is done if we are already in order
|
||||
if !less_than(&heap[child], &heap[pos]) {
|
||||
return;
|
||||
}
|
||||
heap.swap(pos, child);
|
||||
pos = child;
|
||||
child = 2 * pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
|
||||
/// If all base iterators are sorted (ascending), the result is sorted.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
///
|
||||
/// See [`.kmerge()`](../trait.Itertools.html#method.kmerge) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub type KMerge<I> = KMergeBy<I, KMergeByLt>;
|
||||
|
||||
pub trait KMergePredicate<T> {
|
||||
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct KMergeByLt;
|
||||
|
||||
impl<T: PartialOrd> KMergePredicate<T> for KMergeByLt {
|
||||
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
|
||||
a < b
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F: FnMut(&T, &T)->bool> KMergePredicate<T> for F {
|
||||
fn kmerge_pred(&mut self, a: &T, b: &T) -> bool {
|
||||
self(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an iterator that merges elements of the contained iterators using
|
||||
/// the ordering function.
|
||||
///
|
||||
/// Equivalent to `iterable.into_iter().kmerge()`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::kmerge;
|
||||
///
|
||||
/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
|
||||
/// /* loop body */
|
||||
/// }
|
||||
/// ```
|
||||
pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
|
||||
where I: IntoIterator,
|
||||
I::Item: IntoIterator,
|
||||
<<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd
|
||||
{
|
||||
kmerge_by(iterable, KMergeByLt)
|
||||
}
|
||||
|
||||
/// An iterator adaptor that merges an abitrary number of base iterators
|
||||
/// according to an ordering function.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
///
|
||||
/// See [`.kmerge_by()`](../trait.Itertools.html#method.kmerge_by) for more
|
||||
/// information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct KMergeBy<I, F>
|
||||
where I: Iterator,
|
||||
{
|
||||
heap: Vec<HeadTail<I>>,
|
||||
less_than: F,
|
||||
}
|
||||
|
||||
impl<I, F> fmt::Debug for KMergeBy<I, F>
|
||||
where I: Iterator + fmt::Debug,
|
||||
I::Item: fmt::Debug,
|
||||
{
|
||||
debug_fmt_fields!(KMergeBy, heap);
|
||||
}
|
||||
|
||||
/// Create an iterator that merges elements of the contained iterators.
|
||||
///
|
||||
/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`.
|
||||
pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
|
||||
-> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
|
||||
where I: IntoIterator,
|
||||
I::Item: IntoIterator,
|
||||
F: KMergePredicate<<<I as IntoIterator>::Item as IntoIterator>::Item>,
|
||||
{
|
||||
let iter = iterable.into_iter();
|
||||
let (lower, _) = iter.size_hint();
|
||||
let mut heap: Vec<_> = Vec::with_capacity(lower);
|
||||
heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
|
||||
heapify(&mut heap, |a, b| less_than.kmerge_pred(&a.head, &b.head));
|
||||
KMergeBy { heap, less_than }
|
||||
}
|
||||
|
||||
impl<I, F> Clone for KMergeBy<I, F>
|
||||
where I: Iterator + Clone,
|
||||
I::Item: Clone,
|
||||
F: Clone,
|
||||
{
|
||||
clone_fields!(heap, less_than);
|
||||
}
|
||||
|
||||
impl<I, F> Iterator for KMergeBy<I, F>
|
||||
where I: Iterator,
|
||||
F: KMergePredicate<I::Item>
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.heap.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let result = if let Some(next) = self.heap[0].next() {
|
||||
next
|
||||
} else {
|
||||
self.heap.swap_remove(0).head
|
||||
};
|
||||
let less_than = &mut self.less_than;
|
||||
sift_down(&mut self.heap, 0, |a, b| less_than.kmerge_pred(&a.head, &b.head));
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.heap.iter()
|
||||
.map(|i| i.size_hint())
|
||||
.fold1(size_hint::add)
|
||||
.unwrap_or((0, Some(0)))
|
||||
}
|
||||
}
|
59
vendor/itertools/src/lazy_buffer.rs
vendored
Normal file
59
vendor/itertools/src/lazy_buffer.rs
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
use std::ops::Index;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LazyBuffer<I: Iterator> {
|
||||
pub it: I,
|
||||
done: bool,
|
||||
buffer: Vec<I::Item>,
|
||||
}
|
||||
|
||||
impl<I> LazyBuffer<I>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
pub fn new(it: I) -> LazyBuffer<I> {
|
||||
LazyBuffer {
|
||||
it,
|
||||
done: false,
|
||||
buffer: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.buffer.len()
|
||||
}
|
||||
|
||||
pub fn is_done(&self) -> bool {
|
||||
self.done
|
||||
}
|
||||
|
||||
pub fn get_next(&mut self) -> bool {
|
||||
if self.done {
|
||||
return false;
|
||||
}
|
||||
let next_item = self.it.next();
|
||||
match next_item {
|
||||
Some(x) => {
|
||||
self.buffer.push(x);
|
||||
true
|
||||
}
|
||||
None => {
|
||||
self.done = true;
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, J> Index<J> for LazyBuffer<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Sized,
|
||||
Vec<I::Item>: Index<J>
|
||||
{
|
||||
type Output = <Vec<I::Item> as Index<J>>::Output;
|
||||
|
||||
fn index(&self, _index: J) -> &Self::Output {
|
||||
self.buffer.index(_index)
|
||||
}
|
||||
}
|
2721
vendor/itertools/src/lib.rs
vendored
Normal file
2721
vendor/itertools/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
167
vendor/itertools/src/merge_join.rs
vendored
Normal file
167
vendor/itertools/src/merge_join.rs
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::iter::Fuse;
|
||||
use std::fmt;
|
||||
|
||||
use super::adaptors::{PutBack, put_back};
|
||||
use crate::either_or_both::EitherOrBoth;
|
||||
|
||||
/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
|
||||
///
|
||||
/// See [`.merge_join_by()`](trait.Itertools.html#method.merge_join_by) for more information.
|
||||
pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
|
||||
-> MergeJoinBy<I::IntoIter, J::IntoIter, F>
|
||||
where I: IntoIterator,
|
||||
J: IntoIterator,
|
||||
F: FnMut(&I::Item, &J::Item) -> Ordering
|
||||
{
|
||||
MergeJoinBy {
|
||||
left: put_back(left.into_iter().fuse()),
|
||||
right: put_back(right.into_iter().fuse()),
|
||||
cmp_fn,
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
|
||||
///
|
||||
/// See [`.merge_join_by()`](../trait.Itertools.html#method.merge_join_by) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct MergeJoinBy<I: Iterator, J: Iterator, F> {
|
||||
left: PutBack<Fuse<I>>,
|
||||
right: PutBack<Fuse<J>>,
|
||||
cmp_fn: F
|
||||
}
|
||||
|
||||
impl<I, J, F> Clone for MergeJoinBy<I, J, F>
|
||||
where I: Iterator,
|
||||
J: Iterator,
|
||||
PutBack<Fuse<I>>: Clone,
|
||||
PutBack<Fuse<J>>: Clone,
|
||||
F: Clone,
|
||||
{
|
||||
clone_fields!(left, right, cmp_fn);
|
||||
}
|
||||
|
||||
impl<I, J, F> fmt::Debug for MergeJoinBy<I, J, F>
|
||||
where I: Iterator + fmt::Debug,
|
||||
I::Item: fmt::Debug,
|
||||
J: Iterator + fmt::Debug,
|
||||
J::Item: fmt::Debug,
|
||||
{
|
||||
debug_fmt_fields!(MergeJoinBy, left, right);
|
||||
}
|
||||
|
||||
impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
|
||||
where I: Iterator,
|
||||
J: Iterator,
|
||||
F: FnMut(&I::Item, &J::Item) -> Ordering
|
||||
{
|
||||
type Item = EitherOrBoth<I::Item, J::Item>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match (self.left.next(), self.right.next()) {
|
||||
(None, None) => None,
|
||||
(Some(left), None) =>
|
||||
Some(EitherOrBoth::Left(left)),
|
||||
(None, Some(right)) =>
|
||||
Some(EitherOrBoth::Right(right)),
|
||||
(Some(left), Some(right)) => {
|
||||
match (self.cmp_fn)(&left, &right) {
|
||||
Ordering::Equal =>
|
||||
Some(EitherOrBoth::Both(left, right)),
|
||||
Ordering::Less => {
|
||||
self.right.put_back(right);
|
||||
Some(EitherOrBoth::Left(left))
|
||||
},
|
||||
Ordering::Greater => {
|
||||
self.left.put_back(left);
|
||||
Some(EitherOrBoth::Right(right))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (a_lower, a_upper) = self.left.size_hint();
|
||||
let (b_lower, b_upper) = self.right.size_hint();
|
||||
|
||||
let lower = ::std::cmp::max(a_lower, b_lower);
|
||||
|
||||
let upper = match (a_upper, b_upper) {
|
||||
(Some(x), Some(y)) => x.checked_add(y),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
(lower, upper)
|
||||
}
|
||||
|
||||
fn count(mut self) -> usize {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
match (self.left.next(), self.right.next()) {
|
||||
(None, None) => break count,
|
||||
(Some(_left), None) => break count + 1 + self.left.into_parts().1.count(),
|
||||
(None, Some(_right)) => break count + 1 + self.right.into_parts().1.count(),
|
||||
(Some(left), Some(right)) => {
|
||||
count += 1;
|
||||
match (self.cmp_fn)(&left, &right) {
|
||||
Ordering::Equal => {}
|
||||
Ordering::Less => self.right.put_back(right),
|
||||
Ordering::Greater => self.left.put_back(left),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<Self::Item> {
|
||||
let mut previous_element = None;
|
||||
loop {
|
||||
match (self.left.next(), self.right.next()) {
|
||||
(None, None) => break previous_element,
|
||||
(Some(left), None) => {
|
||||
break Some(EitherOrBoth::Left(
|
||||
self.left.into_parts().1.last().unwrap_or(left),
|
||||
))
|
||||
}
|
||||
(None, Some(right)) => {
|
||||
break Some(EitherOrBoth::Right(
|
||||
self.right.into_parts().1.last().unwrap_or(right),
|
||||
))
|
||||
}
|
||||
(Some(left), Some(right)) => {
|
||||
previous_element = match (self.cmp_fn)(&left, &right) {
|
||||
Ordering::Equal => Some(EitherOrBoth::Both(left, right)),
|
||||
Ordering::Less => {
|
||||
self.right.put_back(right);
|
||||
Some(EitherOrBoth::Left(left))
|
||||
}
|
||||
Ordering::Greater => {
|
||||
self.left.put_back(left);
|
||||
Some(EitherOrBoth::Right(right))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
|
||||
loop {
|
||||
if n == 0 {
|
||||
break self.next();
|
||||
}
|
||||
n -= 1;
|
||||
match (self.left.next(), self.right.next()) {
|
||||
(None, None) => break None,
|
||||
(Some(_left), None) => break self.left.nth(n).map(EitherOrBoth::Left),
|
||||
(None, Some(_right)) => break self.right.nth(n).map(EitherOrBoth::Right),
|
||||
(Some(left), Some(right)) => match (self.cmp_fn)(&left, &right) {
|
||||
Ordering::Equal => {}
|
||||
Ordering::Less => self.right.put_back(right),
|
||||
Ordering::Greater => self.left.put_back(left),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
114
vendor/itertools/src/minmax.rs
vendored
Normal file
114
vendor/itertools/src/minmax.rs
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
|
||||
/// `MinMaxResult` is an enum returned by `minmax`. See `Itertools::minmax()` for
|
||||
/// more detail.
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum MinMaxResult<T> {
|
||||
/// Empty iterator
|
||||
NoElements,
|
||||
|
||||
/// Iterator with one element, so the minimum and maximum are the same
|
||||
OneElement(T),
|
||||
|
||||
/// More than one element in the iterator, the first element is not larger
|
||||
/// than the second
|
||||
MinMax(T, T)
|
||||
}
|
||||
|
||||
impl<T: Clone> MinMaxResult<T> {
|
||||
/// `into_option` creates an `Option` of type `(T, T)`. The returned `Option`
|
||||
/// has variant `None` if and only if the `MinMaxResult` has variant
|
||||
/// `NoElements`. Otherwise `Some((x, y))` is returned where `x <= y`.
|
||||
/// If the `MinMaxResult` has variant `OneElement(x)`, performing this
|
||||
/// operation will make one clone of `x`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::MinMaxResult::{self, NoElements, OneElement, MinMax};
|
||||
///
|
||||
/// let r: MinMaxResult<i32> = NoElements;
|
||||
/// assert_eq!(r.into_option(), None);
|
||||
///
|
||||
/// let r = OneElement(1);
|
||||
/// assert_eq!(r.into_option(), Some((1, 1)));
|
||||
///
|
||||
/// let r = MinMax(1, 2);
|
||||
/// assert_eq!(r.into_option(), Some((1, 2)));
|
||||
/// ```
|
||||
pub fn into_option(self) -> Option<(T,T)> {
|
||||
match self {
|
||||
MinMaxResult::NoElements => None,
|
||||
MinMaxResult::OneElement(x) => Some((x.clone(), x)),
|
||||
MinMaxResult::MinMax(x, y) => Some((x, y))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation guts for `minmax` and `minmax_by_key`.
|
||||
pub fn minmax_impl<I, K, F, L>(mut it: I, mut key_for: F,
|
||||
mut lt: L) -> MinMaxResult<I::Item>
|
||||
where I: Iterator,
|
||||
F: FnMut(&I::Item) -> K,
|
||||
L: FnMut(&I::Item, &I::Item, &K, &K) -> bool,
|
||||
{
|
||||
let (mut min, mut max, mut min_key, mut max_key) = match it.next() {
|
||||
None => return MinMaxResult::NoElements,
|
||||
Some(x) => {
|
||||
match it.next() {
|
||||
None => return MinMaxResult::OneElement(x),
|
||||
Some(y) => {
|
||||
let xk = key_for(&x);
|
||||
let yk = key_for(&y);
|
||||
if !lt(&y, &x, &yk, &xk) {(x, y, xk, yk)} else {(y, x, yk, xk)}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
loop {
|
||||
// `first` and `second` are the two next elements we want to look
|
||||
// at. We first compare `first` and `second` (#1). The smaller one
|
||||
// is then compared to current minimum (#2). The larger one is
|
||||
// compared to current maximum (#3). This way we do 3 comparisons
|
||||
// for 2 elements.
|
||||
let first = match it.next() {
|
||||
None => break,
|
||||
Some(x) => x
|
||||
};
|
||||
let second = match it.next() {
|
||||
None => {
|
||||
let first_key = key_for(&first);
|
||||
if lt(&first, &min, &first_key, &min_key) {
|
||||
min = first;
|
||||
} else if !lt(&first, &max, &first_key, &max_key) {
|
||||
max = first;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Some(x) => x
|
||||
};
|
||||
let first_key = key_for(&first);
|
||||
let second_key = key_for(&second);
|
||||
if !lt(&second, &first, &second_key, &first_key) {
|
||||
if lt(&first, &min, &first_key, &min_key) {
|
||||
min = first;
|
||||
min_key = first_key;
|
||||
}
|
||||
if !lt(&second, &max, &second_key, &max_key) {
|
||||
max = second;
|
||||
max_key = second_key;
|
||||
}
|
||||
} else {
|
||||
if lt(&second, &min, &second_key, &min_key) {
|
||||
min = second;
|
||||
min_key = second_key;
|
||||
}
|
||||
if !lt(&first, &max, &first_key, &max_key) {
|
||||
max = first;
|
||||
max_key = first_key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MinMaxResult::MinMax(min, max)
|
||||
}
|
102
vendor/itertools/src/multipeek_impl.rs
vendored
Normal file
102
vendor/itertools/src/multipeek_impl.rs
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
use std::iter::Fuse;
|
||||
use std::collections::VecDeque;
|
||||
use crate::size_hint;
|
||||
use crate::PeekingNext;
|
||||
|
||||
/// See [`multipeek()`](../fn.multipeek.html) for more information.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MultiPeek<I>
|
||||
where I: Iterator
|
||||
{
|
||||
iter: Fuse<I>,
|
||||
buf: VecDeque<I::Item>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
/// An iterator adaptor that allows the user to peek at multiple `.next()`
|
||||
/// values without advancing the base iterator.
|
||||
pub fn multipeek<I>(iterable: I) -> MultiPeek<I::IntoIter>
|
||||
where I: IntoIterator
|
||||
{
|
||||
MultiPeek {
|
||||
iter: iterable.into_iter().fuse(),
|
||||
buf: VecDeque::new(),
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> MultiPeek<I>
|
||||
where I: Iterator
|
||||
{
|
||||
/// Reset the peeking “cursor”
|
||||
pub fn reset_peek(&mut self) {
|
||||
self.index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator> MultiPeek<I> {
|
||||
/// Works exactly like `.next()` with the only difference that it doesn't
|
||||
/// advance itself. `.peek()` can be called multiple times, to peek
|
||||
/// further ahead.
|
||||
pub fn peek(&mut self) -> Option<&I::Item> {
|
||||
let ret = if self.index < self.buf.len() {
|
||||
Some(&self.buf[self.index])
|
||||
} else {
|
||||
match self.iter.next() {
|
||||
Some(x) => {
|
||||
self.buf.push_back(x);
|
||||
Some(&self.buf[self.index])
|
||||
}
|
||||
None => return None,
|
||||
}
|
||||
};
|
||||
|
||||
self.index += 1;
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> PeekingNext for MultiPeek<I>
|
||||
where I: Iterator,
|
||||
{
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where F: FnOnce(&Self::Item) -> bool
|
||||
{
|
||||
if self.buf.is_empty() {
|
||||
if let Some(r) = self.peek() {
|
||||
if !accept(r) { return None }
|
||||
}
|
||||
} else {
|
||||
if let Some(r) = self.buf.get(0) {
|
||||
if !accept(r) { return None }
|
||||
}
|
||||
}
|
||||
self.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for MultiPeek<I>
|
||||
where I: Iterator
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
self.index = 0;
|
||||
if self.buf.is_empty() {
|
||||
self.iter.next()
|
||||
} else {
|
||||
self.buf.pop_front()
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
size_hint::add_scalar(self.iter.size_hint(), self.buf.len())
|
||||
}
|
||||
}
|
||||
|
||||
// Same size
|
||||
impl<I> ExactSizeIterator for MultiPeek<I>
|
||||
where I: ExactSizeIterator
|
||||
{}
|
||||
|
||||
|
83
vendor/itertools/src/pad_tail.rs
vendored
Normal file
83
vendor/itertools/src/pad_tail.rs
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
use std::iter::Fuse;
|
||||
use crate::size_hint;
|
||||
|
||||
/// An iterator adaptor that pads a sequence to a minimum length by filling
|
||||
/// missing elements using a closure.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
///
|
||||
/// See [`.pad_using()`](../trait.Itertools.html#method.pad_using) for more information.
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct PadUsing<I, F> {
|
||||
iter: Fuse<I>,
|
||||
min: usize,
|
||||
pos: usize,
|
||||
filler: F,
|
||||
}
|
||||
|
||||
/// Create a new **PadUsing** iterator.
|
||||
pub fn pad_using<I, F>(iter: I, min: usize, filler: F) -> PadUsing<I, F>
|
||||
where I: Iterator,
|
||||
F: FnMut(usize) -> I::Item
|
||||
{
|
||||
PadUsing {
|
||||
iter: iter.fuse(),
|
||||
min,
|
||||
pos: 0,
|
||||
filler,
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, F> Iterator for PadUsing<I, F>
|
||||
where I: Iterator,
|
||||
F: FnMut(usize) -> I::Item
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
match self.iter.next() {
|
||||
None => {
|
||||
if self.pos < self.min {
|
||||
let e = Some((self.filler)(self.pos));
|
||||
self.pos += 1;
|
||||
e
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
e => {
|
||||
self.pos += 1;
|
||||
e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let tail = self.min.saturating_sub(self.pos);
|
||||
size_hint::max(self.iter.size_hint(), (tail, Some(tail)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, F> DoubleEndedIterator for PadUsing<I, F>
|
||||
where I: DoubleEndedIterator + ExactSizeIterator,
|
||||
F: FnMut(usize) -> I::Item
|
||||
{
|
||||
fn next_back(&mut self) -> Option<I::Item> {
|
||||
if self.min == 0 {
|
||||
self.iter.next_back()
|
||||
} else if self.iter.len() >= self.min {
|
||||
self.min -= 1;
|
||||
self.iter.next_back()
|
||||
} else {
|
||||
self.min -= 1;
|
||||
Some((self.filler)(self.min))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, F> ExactSizeIterator for PadUsing<I, F>
|
||||
where I: ExactSizeIterator,
|
||||
F: FnMut(usize) -> I::Item
|
||||
{}
|
148
vendor/itertools/src/peeking_take_while.rs
vendored
Normal file
148
vendor/itertools/src/peeking_take_while.rs
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
use std::iter::Peekable;
|
||||
use crate::PutBack;
|
||||
#[cfg(feature = "use_std")]
|
||||
use crate::PutBackN;
|
||||
|
||||
/// An iterator that allows peeking at an element before deciding to accept it.
|
||||
///
|
||||
/// See [`.peeking_take_while()`](trait.Itertools.html#method.peeking_take_while)
|
||||
/// for more information.
|
||||
///
|
||||
/// This is implemented by peeking adaptors like peekable and put back,
|
||||
/// but also by a few iterators that can be peeked natively, like the slice’s
|
||||
/// by reference iterator (`std::slice::Iter`).
|
||||
pub trait PeekingNext : Iterator {
|
||||
/// Pass a reference to the next iterator element to the closure `accept`;
|
||||
/// if `accept` returns true, return it as the next element,
|
||||
/// else None.
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where F: FnOnce(&Self::Item) -> bool;
|
||||
}
|
||||
|
||||
impl<I> PeekingNext for Peekable<I>
|
||||
where I: Iterator,
|
||||
{
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where F: FnOnce(&Self::Item) -> bool
|
||||
{
|
||||
if let Some(r) = self.peek() {
|
||||
if !accept(r) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
self.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> PeekingNext for PutBack<I>
|
||||
where I: Iterator,
|
||||
{
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where F: FnOnce(&Self::Item) -> bool
|
||||
{
|
||||
if let Some(r) = self.next() {
|
||||
if !accept(&r) {
|
||||
self.put_back(r);
|
||||
return None;
|
||||
}
|
||||
Some(r)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "use_std")]
|
||||
impl<I> PeekingNext for PutBackN<I>
|
||||
where I: Iterator,
|
||||
{
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where F: FnOnce(&Self::Item) -> bool
|
||||
{
|
||||
if let Some(r) = self.next() {
|
||||
if !accept(&r) {
|
||||
self.put_back(r);
|
||||
return None;
|
||||
}
|
||||
Some(r)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator adaptor that takes items while a closure returns `true`.
|
||||
///
|
||||
/// See [`.peeking_take_while()`](../trait.Itertools.html#method.peeking_take_while)
|
||||
/// for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct PeekingTakeWhile<'a, I: 'a, F>
|
||||
where I: Iterator,
|
||||
{
|
||||
iter: &'a mut I,
|
||||
f: F,
|
||||
}
|
||||
|
||||
/// Create a PeekingTakeWhile
|
||||
pub fn peeking_take_while<I, F>(iter: &mut I, f: F) -> PeekingTakeWhile<I, F>
|
||||
where I: Iterator,
|
||||
{
|
||||
PeekingTakeWhile {
|
||||
iter,
|
||||
f,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F>
|
||||
where I: PeekingNext,
|
||||
F: FnMut(&I::Item) -> bool,
|
||||
|
||||
{
|
||||
type Item = I::Item;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.peeking_next(&mut self.f)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (_, hi) = self.iter.size_hint();
|
||||
(0, hi)
|
||||
}
|
||||
}
|
||||
|
||||
// Some iterators are so lightweight we can simply clone them to save their
|
||||
// state and use that for peeking.
|
||||
macro_rules! peeking_next_by_clone {
|
||||
([$($typarm:tt)*] $type_:ty) => {
|
||||
impl<$($typarm)*> PeekingNext for $type_ {
|
||||
fn peeking_next<F>(&mut self, accept: F) -> Option<Self::Item>
|
||||
where F: FnOnce(&Self::Item) -> bool
|
||||
{
|
||||
let saved_state = self.clone();
|
||||
if let Some(r) = self.next() {
|
||||
if !accept(&r) {
|
||||
*self = saved_state;
|
||||
} else {
|
||||
return Some(r)
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peeking_next_by_clone! { ['a, T] ::std::slice::Iter<'a, T> }
|
||||
peeking_next_by_clone! { ['a] ::std::str::Chars<'a> }
|
||||
peeking_next_by_clone! { ['a] ::std::str::CharIndices<'a> }
|
||||
peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> }
|
||||
peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> }
|
||||
peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> }
|
||||
peeking_next_by_clone! { [T] ::std::iter::Empty<T> }
|
||||
#[cfg(feature = "use_std")]
|
||||
peeking_next_by_clone! { ['a, T] ::std::collections::linked_list::Iter<'a, T> }
|
||||
#[cfg(feature = "use_std")]
|
||||
peeking_next_by_clone! { ['a, T] ::std::collections::vec_deque::Iter<'a, T> }
|
||||
|
||||
// cloning a Rev has no extra overhead; peekable and put backs are never DEI.
|
||||
peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator]
|
||||
::std::iter::Rev<I> }
|
279
vendor/itertools/src/permutations.rs
vendored
Normal file
279
vendor/itertools/src/permutations.rs
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
use std::fmt;
|
||||
use std::iter::once;
|
||||
|
||||
use super::lazy_buffer::LazyBuffer;
|
||||
|
||||
/// An iterator adaptor that iterates through all the `k`-permutations of the
|
||||
/// elements from an iterator.
|
||||
///
|
||||
/// See [`.permutations()`](../trait.Itertools.html#method.permutations) for
|
||||
/// more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct Permutations<I: Iterator> {
|
||||
vals: LazyBuffer<I>,
|
||||
state: PermutationState,
|
||||
}
|
||||
|
||||
impl<I> Clone for Permutations<I>
|
||||
where I: Clone + Iterator,
|
||||
I::Item: Clone,
|
||||
{
|
||||
clone_fields!(vals, state);
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum PermutationState {
|
||||
StartUnknownLen {
|
||||
k: usize,
|
||||
},
|
||||
OngoingUnknownLen {
|
||||
k: usize,
|
||||
min_n: usize,
|
||||
},
|
||||
Complete(CompleteState),
|
||||
Empty,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum CompleteState {
|
||||
Start {
|
||||
n: usize,
|
||||
k: usize,
|
||||
},
|
||||
Ongoing {
|
||||
indices: Vec<usize>,
|
||||
cycles: Vec<usize>,
|
||||
}
|
||||
}
|
||||
|
||||
enum CompleteStateRemaining {
|
||||
Known(usize),
|
||||
Overflow,
|
||||
}
|
||||
|
||||
impl<I> fmt::Debug for Permutations<I>
|
||||
where I: Iterator + fmt::Debug,
|
||||
I::Item: fmt::Debug,
|
||||
{
|
||||
debug_fmt_fields!(Permutations, vals, state);
|
||||
}
|
||||
|
||||
pub fn permutations<I: Iterator>(iter: I, k: usize) -> Permutations<I> {
|
||||
let mut vals = LazyBuffer::new(iter);
|
||||
|
||||
if k == 0 {
|
||||
// Special case, yields single empty vec; `n` is irrelevant
|
||||
let state = PermutationState::Complete(CompleteState::Start { n: 0, k: 0 });
|
||||
|
||||
return Permutations {
|
||||
vals,
|
||||
state
|
||||
};
|
||||
}
|
||||
|
||||
let mut enough_vals = true;
|
||||
|
||||
while vals.len() < k {
|
||||
if !vals.get_next() {
|
||||
enough_vals = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let state = if enough_vals {
|
||||
PermutationState::StartUnknownLen { k }
|
||||
} else {
|
||||
PermutationState::Empty
|
||||
};
|
||||
|
||||
Permutations {
|
||||
vals,
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for Permutations<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone
|
||||
{
|
||||
type Item = Vec<I::Item>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.advance();
|
||||
|
||||
let &mut Permutations { ref vals, ref state } = self;
|
||||
|
||||
match state {
|
||||
&PermutationState::StartUnknownLen { .. } => panic!("unexpected iterator state"),
|
||||
&PermutationState::OngoingUnknownLen { k, min_n } => {
|
||||
let latest_idx = min_n - 1;
|
||||
let indices = (0..(k - 1)).chain(once(latest_idx));
|
||||
|
||||
Some(indices.map(|i| vals[i].clone()).collect())
|
||||
}
|
||||
&PermutationState::Complete(CompleteState::Start { .. }) => None,
|
||||
&PermutationState::Complete(CompleteState::Ongoing { ref indices, ref cycles }) => {
|
||||
let k = cycles.len();
|
||||
|
||||
Some(indices[0..k].iter().map(|&i| vals[i].clone()).collect())
|
||||
},
|
||||
&PermutationState::Empty => None
|
||||
}
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
let Permutations { vals, state } = self;
|
||||
|
||||
fn from_complete(complete_state: CompleteState) -> usize {
|
||||
match complete_state.remaining() {
|
||||
CompleteStateRemaining::Known(count) => count,
|
||||
CompleteStateRemaining::Overflow => {
|
||||
panic!("Iterator count greater than usize::MAX");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match state {
|
||||
PermutationState::StartUnknownLen { k } => {
|
||||
let n = vals.len() + vals.it.count();
|
||||
let complete_state = CompleteState::Start { n, k };
|
||||
|
||||
from_complete(complete_state)
|
||||
}
|
||||
PermutationState::OngoingUnknownLen { k, min_n } => {
|
||||
let prev_iteration_count = min_n - k + 1;
|
||||
let n = vals.len() + vals.it.count();
|
||||
let complete_state = CompleteState::Start { n, k };
|
||||
|
||||
from_complete(complete_state) - prev_iteration_count
|
||||
},
|
||||
PermutationState::Complete(state) => from_complete(state),
|
||||
PermutationState::Empty => 0
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match self.state {
|
||||
PermutationState::StartUnknownLen { .. } |
|
||||
PermutationState::OngoingUnknownLen { .. } => (0, None), // TODO can we improve this lower bound?
|
||||
PermutationState::Complete(ref state) => match state.remaining() {
|
||||
CompleteStateRemaining::Known(count) => (count, Some(count)),
|
||||
CompleteStateRemaining::Overflow => (::std::usize::MAX, None)
|
||||
}
|
||||
PermutationState::Empty => (0, Some(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Permutations<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone
|
||||
{
|
||||
fn advance(&mut self) {
|
||||
let &mut Permutations { ref mut vals, ref mut state } = self;
|
||||
|
||||
*state = match state {
|
||||
&mut PermutationState::StartUnknownLen { k } => {
|
||||
PermutationState::OngoingUnknownLen { k, min_n: k }
|
||||
}
|
||||
&mut PermutationState::OngoingUnknownLen { k, min_n } => {
|
||||
if vals.get_next() {
|
||||
PermutationState::OngoingUnknownLen { k, min_n: min_n + 1 }
|
||||
} else {
|
||||
let n = min_n;
|
||||
let prev_iteration_count = n - k + 1;
|
||||
let mut complete_state = CompleteState::Start { n, k };
|
||||
|
||||
// Advance the complete-state iterator to the correct point
|
||||
for _ in 0..(prev_iteration_count + 1) {
|
||||
complete_state.advance();
|
||||
}
|
||||
|
||||
PermutationState::Complete(complete_state)
|
||||
}
|
||||
}
|
||||
&mut PermutationState::Complete(ref mut state) => {
|
||||
state.advance();
|
||||
|
||||
return;
|
||||
}
|
||||
&mut PermutationState::Empty => { return; }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl CompleteState {
|
||||
fn advance(&mut self) {
|
||||
*self = match self {
|
||||
&mut CompleteState::Start { n, k } => {
|
||||
let indices = (0..n).collect();
|
||||
let cycles = ((n - k)..n).rev().collect();
|
||||
|
||||
CompleteState::Ongoing {
|
||||
cycles,
|
||||
indices
|
||||
}
|
||||
},
|
||||
&mut CompleteState::Ongoing { ref mut indices, ref mut cycles } => {
|
||||
let n = indices.len();
|
||||
let k = cycles.len();
|
||||
|
||||
for i in (0..k).rev() {
|
||||
if cycles[i] == 0 {
|
||||
cycles[i] = n - i - 1;
|
||||
|
||||
let to_push = indices.remove(i);
|
||||
indices.push(to_push);
|
||||
} else {
|
||||
let swap_index = n - cycles[i];
|
||||
indices.swap(i, swap_index);
|
||||
|
||||
cycles[i] -= 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CompleteState::Start { n, k }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remaining(&self) -> CompleteStateRemaining {
|
||||
use self::CompleteStateRemaining::{Known, Overflow};
|
||||
|
||||
match self {
|
||||
&CompleteState::Start { n, k } => {
|
||||
if n < k {
|
||||
return Known(0);
|
||||
}
|
||||
|
||||
let count: Option<usize> = (n - k + 1..n + 1).fold(Some(1), |acc, i| {
|
||||
acc.and_then(|acc| acc.checked_mul(i))
|
||||
});
|
||||
|
||||
match count {
|
||||
Some(count) => Known(count),
|
||||
None => Overflow
|
||||
}
|
||||
}
|
||||
&CompleteState::Ongoing { ref indices, ref cycles } => {
|
||||
let mut count: usize = 0;
|
||||
|
||||
for (i, &c) in cycles.iter().enumerate() {
|
||||
let radix = indices.len() - i;
|
||||
let next_count = count.checked_mul(radix)
|
||||
.and_then(|count| count.checked_add(c));
|
||||
|
||||
count = match next_count {
|
||||
Some(count) => count,
|
||||
None => { return Overflow; }
|
||||
};
|
||||
}
|
||||
|
||||
Known(count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
81
vendor/itertools/src/process_results_impl.rs
vendored
Normal file
81
vendor/itertools/src/process_results_impl.rs
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
|
||||
/// An iterator that produces only the `T` values as long as the
|
||||
/// inner iterator produces `Ok(T)`.
|
||||
///
|
||||
/// Used by [`process_results`](../fn.process_results.html), see its docs
|
||||
/// for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
#[derive(Debug)]
|
||||
pub struct ProcessResults<'a, I, E: 'a> {
|
||||
error: &'a mut Result<(), E>,
|
||||
iter: I,
|
||||
}
|
||||
|
||||
impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E>
|
||||
where I: Iterator<Item = Result<T, E>>
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iter.next() {
|
||||
Some(Ok(x)) => Some(x),
|
||||
Some(Err(e)) => {
|
||||
*self.error = Err(e);
|
||||
None
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (_, hi) = self.iter.size_hint();
|
||||
(0, hi)
|
||||
}
|
||||
}
|
||||
|
||||
/// “Lift” a function of the values of an iterator so that it can process
|
||||
/// an iterator of `Result` values instead.
|
||||
///
|
||||
/// `iterable` is an iterator or iterable with `Result<T, E>` elements, where
|
||||
/// `T` is the value type and `E` the error type.
|
||||
///
|
||||
/// `processor` is a closure that receives an adapted version of the iterable
|
||||
/// as the only argument — the adapted iterator produces elements of type `T`,
|
||||
/// as long as the original iterator produces `Ok` values.
|
||||
///
|
||||
/// If the original iterable produces an error at any point, the adapted
|
||||
/// iterator ends and the `process_results` function will return the
|
||||
/// error iself.
|
||||
///
|
||||
/// Otherwise, the return value from the closure is returned wrapped
|
||||
/// inside `Ok`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::process_results;
|
||||
///
|
||||
/// type R = Result<i32, &'static str>;
|
||||
///
|
||||
/// let first_values: Vec<R> = vec![Ok(1), Ok(0), Ok(3)];
|
||||
/// let second_values: Vec<R> = vec![Ok(2), Ok(1), Err("overflow")];
|
||||
///
|
||||
/// // “Lift” the iterator .max() method to work on the values in Results using process_results
|
||||
///
|
||||
/// let first_max = process_results(first_values, |iter| iter.max().unwrap_or(0));
|
||||
/// let second_max = process_results(second_values, |iter| iter.max().unwrap_or(0));
|
||||
///
|
||||
/// assert_eq!(first_max, Ok(3));
|
||||
/// assert!(second_max.is_err());
|
||||
/// ```
|
||||
pub fn process_results<I, F, T, E, R>(iterable: I, processor: F) -> Result<R, E>
|
||||
where I: IntoIterator<Item = Result<T, E>>,
|
||||
F: FnOnce(ProcessResults<I::IntoIter, E>) -> R
|
||||
{
|
||||
let iter = iterable.into_iter();
|
||||
let mut error = Ok(());
|
||||
|
||||
let result = processor(ProcessResults { error: &mut error, iter });
|
||||
|
||||
error.map(|_| result)
|
||||
}
|
63
vendor/itertools/src/put_back_n_impl.rs
vendored
Normal file
63
vendor/itertools/src/put_back_n_impl.rs
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
use crate::size_hint;
|
||||
|
||||
/// An iterator adaptor that allows putting multiple
|
||||
/// items in front of the iterator.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PutBackN<I: Iterator> {
|
||||
top: Vec<I::Item>,
|
||||
iter: I,
|
||||
}
|
||||
|
||||
/// Create an iterator where you can put back multiple values to the front
|
||||
/// of the iteration.
|
||||
///
|
||||
/// Iterator element type is `I::Item`.
|
||||
pub fn put_back_n<I>(iterable: I) -> PutBackN<I::IntoIter>
|
||||
where I: IntoIterator
|
||||
{
|
||||
PutBackN {
|
||||
top: Vec::new(),
|
||||
iter: iterable.into_iter(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator> PutBackN<I> {
|
||||
/// Puts x in front of the iterator.
|
||||
/// The values are yielded in order of the most recently put back
|
||||
/// values first.
|
||||
///
|
||||
/// ```rust
|
||||
/// use itertools::put_back_n;
|
||||
///
|
||||
/// let mut it = put_back_n(1..5);
|
||||
/// it.next();
|
||||
/// it.put_back(1);
|
||||
/// it.put_back(0);
|
||||
///
|
||||
/// assert!(itertools::equal(it, 0..5));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn put_back(&mut self, x: I::Item) {
|
||||
self.top.push(x);
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator> Iterator for PutBackN<I> {
|
||||
type Item = I::Item;
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
if self.top.is_empty() {
|
||||
self.iter.next()
|
||||
} else {
|
||||
self.top.pop()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
size_hint::add_scalar(self.iter.size_hint(), self.top.len())
|
||||
}
|
||||
}
|
||||
|
96
vendor/itertools/src/rciter_impl.rs
vendored
Normal file
96
vendor/itertools/src/rciter_impl.rs
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
|
||||
use std::iter::IntoIterator;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
/// A wrapper for `Rc<RefCell<I>>`, that implements the `Iterator` trait.
|
||||
#[derive(Debug)]
|
||||
pub struct RcIter<I> {
|
||||
/// The boxed iterator.
|
||||
pub rciter: Rc<RefCell<I>>,
|
||||
}
|
||||
|
||||
/// Return an iterator inside a `Rc<RefCell<_>>` wrapper.
|
||||
///
|
||||
/// The returned `RcIter` can be cloned, and each clone will refer back to the
|
||||
/// same original iterator.
|
||||
///
|
||||
/// `RcIter` allows doing interesting things like using `.zip()` on an iterator with
|
||||
/// itself, at the cost of runtime borrow checking which may have a performance
|
||||
/// penalty.
|
||||
///
|
||||
/// Iterator element type is `Self::Item`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::rciter;
|
||||
/// use itertools::zip;
|
||||
///
|
||||
/// // In this example a range iterator is created and we iterate it using
|
||||
/// // three separate handles (two of them given to zip).
|
||||
/// // We also use the IntoIterator implementation for `&RcIter`.
|
||||
///
|
||||
/// let mut iter = rciter(0..9);
|
||||
/// let mut z = zip(&iter, &iter);
|
||||
///
|
||||
/// assert_eq!(z.next(), Some((0, 1)));
|
||||
/// assert_eq!(z.next(), Some((2, 3)));
|
||||
/// assert_eq!(z.next(), Some((4, 5)));
|
||||
/// assert_eq!(iter.next(), Some(6));
|
||||
/// assert_eq!(z.next(), Some((7, 8)));
|
||||
/// assert_eq!(z.next(), None);
|
||||
/// ```
|
||||
///
|
||||
/// **Panics** in iterator methods if a borrow error is encountered in the
|
||||
/// iterator methods. It can only happen if the `RcIter` is reentered in
|
||||
/// `.next()`, i.e. if it somehow participates in an “iterator knot”
|
||||
/// where it is an adaptor of itself.
|
||||
pub fn rciter<I>(iterable: I) -> RcIter<I::IntoIter>
|
||||
where I: IntoIterator
|
||||
{
|
||||
RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) }
|
||||
}
|
||||
|
||||
impl<I> Clone for RcIter<I> {
|
||||
#[inline]
|
||||
clone_fields!(rciter);
|
||||
}
|
||||
|
||||
impl<A, I> Iterator for RcIter<I>
|
||||
where I: Iterator<Item = A>
|
||||
{
|
||||
type Item = A;
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
self.rciter.borrow_mut().next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
// To work sanely with other API that assume they own an iterator,
|
||||
// so it can't change in other places, we can't guarantee as much
|
||||
// in our size_hint. Other clones may drain values under our feet.
|
||||
let (_, hi) = self.rciter.borrow().size_hint();
|
||||
(0, hi)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> DoubleEndedIterator for RcIter<I>
|
||||
where I: DoubleEndedIterator
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<I::Item> {
|
||||
self.rciter.borrow_mut().next_back()
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an iterator from `&RcIter<I>` (by simply cloning it).
|
||||
impl<'a, I> IntoIterator for &'a RcIter<I>
|
||||
where I: Iterator
|
||||
{
|
||||
type Item = I::Item;
|
||||
type IntoIter = RcIter<I>;
|
||||
|
||||
fn into_iter(self) -> RcIter<I> {
|
||||
self.clone()
|
||||
}
|
||||
}
|
54
vendor/itertools/src/repeatn.rs
vendored
Normal file
54
vendor/itertools/src/repeatn.rs
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
/// An iterator that produces *n* repetitions of an element.
|
||||
///
|
||||
/// See [`repeat_n()`](../fn.repeat_n.html) for more information.
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RepeatN<A> {
|
||||
elt: Option<A>,
|
||||
n: usize,
|
||||
}
|
||||
|
||||
/// Create an iterator that produces `n` repetitions of `element`.
|
||||
pub fn repeat_n<A>(element: A, n: usize) -> RepeatN<A>
|
||||
where A: Clone,
|
||||
{
|
||||
if n == 0 {
|
||||
RepeatN { elt: None, n, }
|
||||
} else {
|
||||
RepeatN { elt: Some(element), n, }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> Iterator for RepeatN<A>
|
||||
where A: Clone
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.n > 1 {
|
||||
self.n -= 1;
|
||||
self.elt.as_ref().cloned()
|
||||
} else {
|
||||
self.n = 0;
|
||||
self.elt.take()
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.n, Some(self.n))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> DoubleEndedIterator for RepeatN<A>
|
||||
where A: Clone
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> ExactSizeIterator for RepeatN<A>
|
||||
where A: Clone
|
||||
{}
|
104
vendor/itertools/src/size_hint.rs
vendored
Normal file
104
vendor/itertools/src/size_hint.rs
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
//! Arithmetic on **Iterator** *.size_hint()* values.
|
||||
//!
|
||||
|
||||
use std::usize;
|
||||
use std::cmp;
|
||||
|
||||
/// **SizeHint** is the return type of **Iterator::size_hint()**.
|
||||
pub type SizeHint = (usize, Option<usize>);
|
||||
|
||||
/// Add **SizeHint** correctly.
|
||||
#[inline]
|
||||
pub fn add(a: SizeHint, b: SizeHint) -> SizeHint {
|
||||
let min = a.0.checked_add(b.0).unwrap_or(usize::MAX);
|
||||
let max = match (a.1, b.1) {
|
||||
(Some(x), Some(y)) => x.checked_add(y),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
(min, max)
|
||||
}
|
||||
|
||||
/// Add **x** correctly to a **SizeHint**.
|
||||
#[inline]
|
||||
pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint {
|
||||
let (mut low, mut hi) = sh;
|
||||
low = low.saturating_add(x);
|
||||
hi = hi.and_then(|elt| elt.checked_add(x));
|
||||
(low, hi)
|
||||
}
|
||||
|
||||
/// Sbb **x** correctly to a **SizeHint**.
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint {
|
||||
let (mut low, mut hi) = sh;
|
||||
low = low.saturating_sub(x);
|
||||
hi = hi.map(|elt| elt.saturating_sub(x));
|
||||
(low, hi)
|
||||
}
|
||||
|
||||
|
||||
/// Multiply **SizeHint** correctly
|
||||
///
|
||||
/// ```ignore
|
||||
/// use std::usize;
|
||||
/// use itertools::size_hint;
|
||||
///
|
||||
/// assert_eq!(size_hint::mul((3, Some(4)), (3, Some(4))),
|
||||
/// (9, Some(16)));
|
||||
///
|
||||
/// assert_eq!(size_hint::mul((3, Some(4)), (usize::MAX, None)),
|
||||
/// (usize::MAX, None));
|
||||
///
|
||||
/// assert_eq!(size_hint::mul((3, None), (0, Some(0))),
|
||||
/// (0, Some(0)));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint {
|
||||
let low = a.0.checked_mul(b.0).unwrap_or(usize::MAX);
|
||||
let hi = match (a.1, b.1) {
|
||||
(Some(x), Some(y)) => x.checked_mul(y),
|
||||
(Some(0), None) | (None, Some(0)) => Some(0),
|
||||
_ => None,
|
||||
};
|
||||
(low, hi)
|
||||
}
|
||||
|
||||
/// Multiply **x** correctly with a **SizeHint**.
|
||||
#[inline]
|
||||
pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint {
|
||||
let (mut low, mut hi) = sh;
|
||||
low = low.saturating_mul(x);
|
||||
hi = hi.and_then(|elt| elt.checked_mul(x));
|
||||
(low, hi)
|
||||
}
|
||||
|
||||
/// Return the maximum
|
||||
#[inline]
|
||||
pub fn max(a: SizeHint, b: SizeHint) -> SizeHint {
|
||||
let (a_lower, a_upper) = a;
|
||||
let (b_lower, b_upper) = b;
|
||||
|
||||
let lower = cmp::max(a_lower, b_lower);
|
||||
|
||||
let upper = match (a_upper, b_upper) {
|
||||
(Some(x), Some(y)) => Some(cmp::max(x, y)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
(lower, upper)
|
||||
}
|
||||
|
||||
/// Return the minimum
|
||||
#[inline]
|
||||
pub fn min(a: SizeHint, b: SizeHint) -> SizeHint {
|
||||
let (a_lower, a_upper) = a;
|
||||
let (b_lower, b_upper) = b;
|
||||
let lower = cmp::min(a_lower, b_lower);
|
||||
let upper = match (a_upper, b_upper) {
|
||||
(Some(u1), Some(u2)) => Some(cmp::min(u1, u2)),
|
||||
_ => a_upper.or(b_upper),
|
||||
};
|
||||
(lower, upper)
|
||||
}
|
191
vendor/itertools/src/sources.rs
vendored
Normal file
191
vendor/itertools/src/sources.rs
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
//! Iterators that are sources (produce elements from parameters,
|
||||
//! not from another iterator).
|
||||
#![allow(deprecated)]
|
||||
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
|
||||
/// See [`repeat_call`](../fn.repeat_call.html) for more information.
|
||||
#[derive(Clone)]
|
||||
#[deprecated(note="Use std repeat_with() instead", since="0.8")]
|
||||
pub struct RepeatCall<F> {
|
||||
f: F,
|
||||
}
|
||||
|
||||
impl<F> fmt::Debug for RepeatCall<F>
|
||||
{
|
||||
debug_fmt_fields!(RepeatCall, );
|
||||
}
|
||||
|
||||
/// An iterator source that produces elements indefinitely by calling
|
||||
/// a given closure.
|
||||
///
|
||||
/// Iterator element type is the return type of the closure.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::repeat_call;
|
||||
/// use itertools::Itertools;
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut heap = BinaryHeap::from(vec![2, 5, 3, 7, 8]);
|
||||
///
|
||||
/// // extract each element in sorted order
|
||||
/// for element in repeat_call(|| heap.pop()).while_some() {
|
||||
/// print!("{}", element);
|
||||
/// }
|
||||
///
|
||||
/// itertools::assert_equal(
|
||||
/// repeat_call(|| 1).take(5),
|
||||
/// vec![1, 1, 1, 1, 1]
|
||||
/// );
|
||||
/// ```
|
||||
#[deprecated(note="Use std repeat_with() instead", since="0.8")]
|
||||
pub fn repeat_call<F, A>(function: F) -> RepeatCall<F>
|
||||
where F: FnMut() -> A
|
||||
{
|
||||
RepeatCall { f: function }
|
||||
}
|
||||
|
||||
impl<A, F> Iterator for RepeatCall<F>
|
||||
where F: FnMut() -> A
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
Some((self.f)())
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(usize::max_value(), None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new unfold source with the specified closure as the "iterator
|
||||
/// function" and an initial state to eventually pass to the closure
|
||||
///
|
||||
/// `unfold` is a general iterator builder: it has a mutable state value,
|
||||
/// and a closure with access to the state that produces the next value.
|
||||
///
|
||||
/// This more or less equivalent to a regular struct with an `Iterator`
|
||||
/// implementation, and is useful for one-off iterators.
|
||||
///
|
||||
/// ```
|
||||
/// // an iterator that yields sequential Fibonacci numbers,
|
||||
/// // and stops at the maximum representable value.
|
||||
///
|
||||
/// use itertools::unfold;
|
||||
///
|
||||
/// let (mut x1, mut x2) = (1u32, 1u32);
|
||||
/// let mut fibonacci = unfold((), move |_| {
|
||||
/// // Attempt to get the next Fibonacci number
|
||||
/// let next = x1.saturating_add(x2);
|
||||
///
|
||||
/// // Shift left: ret <- x1 <- x2 <- next
|
||||
/// let ret = x1;
|
||||
/// x1 = x2;
|
||||
/// x2 = next;
|
||||
///
|
||||
/// // If addition has saturated at the maximum, we are finished
|
||||
/// if ret == x1 && ret > 1 {
|
||||
/// return None;
|
||||
/// }
|
||||
///
|
||||
/// Some(ret)
|
||||
/// });
|
||||
///
|
||||
/// itertools::assert_equal(fibonacci.by_ref().take(8),
|
||||
/// vec![1, 1, 2, 3, 5, 8, 13, 21]);
|
||||
/// assert_eq!(fibonacci.last(), Some(2_971_215_073))
|
||||
/// ```
|
||||
pub fn unfold<A, St, F>(initial_state: St, f: F) -> Unfold<St, F>
|
||||
where F: FnMut(&mut St) -> Option<A>
|
||||
{
|
||||
Unfold {
|
||||
f,
|
||||
state: initial_state,
|
||||
}
|
||||
}
|
||||
|
||||
impl<St, F> fmt::Debug for Unfold<St, F>
|
||||
where St: fmt::Debug,
|
||||
{
|
||||
debug_fmt_fields!(Unfold, state);
|
||||
}
|
||||
|
||||
/// See [`unfold`](../fn.unfold.html) for more information.
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
pub struct Unfold<St, F> {
|
||||
f: F,
|
||||
/// Internal state that will be passed to the closure on the next iteration
|
||||
pub state: St,
|
||||
}
|
||||
|
||||
impl<A, St, F> Iterator for Unfold<St, F>
|
||||
where F: FnMut(&mut St) -> Option<A>
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
(self.f)(&mut self.state)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
// no possible known bounds at this point
|
||||
(0, None)
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that infinitely applies function to value and yields results.
|
||||
///
|
||||
/// This `struct` is created by the [`iterate()`] function. See its documentation for more.
|
||||
///
|
||||
/// [`iterate()`]: ../fn.iterate.html
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
pub struct Iterate<St, F> {
|
||||
state: St,
|
||||
f: F,
|
||||
}
|
||||
|
||||
impl<St, F> fmt::Debug for Iterate<St, F>
|
||||
where St: fmt::Debug,
|
||||
{
|
||||
debug_fmt_fields!(Iterate, state);
|
||||
}
|
||||
|
||||
impl<St, F> Iterator for Iterate<St, F>
|
||||
where F: FnMut(&St) -> St
|
||||
{
|
||||
type Item = St;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let next_state = (self.f)(&self.state);
|
||||
Some(mem::replace(&mut self.state, next_state))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(usize::max_value(), None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new iterator that infinitely applies function to value and yields results.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::iterate;
|
||||
///
|
||||
/// itertools::assert_equal(iterate(1, |&i| i * 3).take(5), vec![1, 3, 9, 27, 81]);
|
||||
/// ```
|
||||
pub fn iterate<St, F>(initial_value: St, f: F) -> Iterate<St, F>
|
||||
where F: FnMut(&St) -> St
|
||||
{
|
||||
Iterate {
|
||||
state: initial_value,
|
||||
f,
|
||||
}
|
||||
}
|
78
vendor/itertools/src/tee.rs
vendored
Normal file
78
vendor/itertools/src/tee.rs
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
use super::size_hint;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Common buffer object for the two tee halves
|
||||
#[derive(Debug)]
|
||||
struct TeeBuffer<A, I> {
|
||||
backlog: VecDeque<A>,
|
||||
iter: I,
|
||||
/// The owner field indicates which id should read from the backlog
|
||||
owner: bool,
|
||||
}
|
||||
|
||||
/// One half of an iterator pair where both return the same elements.
|
||||
///
|
||||
/// See [`.tee()`](../trait.Itertools.html#method.tee) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
#[derive(Debug)]
|
||||
pub struct Tee<I>
|
||||
where I: Iterator
|
||||
{
|
||||
rcbuffer: Rc<RefCell<TeeBuffer<I::Item, I>>>,
|
||||
id: bool,
|
||||
}
|
||||
|
||||
pub fn new<I>(iter: I) -> (Tee<I>, Tee<I>)
|
||||
where I: Iterator
|
||||
{
|
||||
let buffer = TeeBuffer{backlog: VecDeque::new(), iter, owner: false};
|
||||
let t1 = Tee{rcbuffer: Rc::new(RefCell::new(buffer)), id: true};
|
||||
let t2 = Tee{rcbuffer: t1.rcbuffer.clone(), id: false};
|
||||
(t1, t2)
|
||||
}
|
||||
|
||||
impl<I> Iterator for Tee<I>
|
||||
where I: Iterator,
|
||||
I::Item: Clone
|
||||
{
|
||||
type Item = I::Item;
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
// .borrow_mut may fail here -- but only if the user has tied some kind of weird
|
||||
// knot where the iterator refers back to itself.
|
||||
let mut buffer = self.rcbuffer.borrow_mut();
|
||||
if buffer.owner == self.id {
|
||||
match buffer.backlog.pop_front() {
|
||||
None => {}
|
||||
some_elt => return some_elt,
|
||||
}
|
||||
}
|
||||
match buffer.iter.next() {
|
||||
None => None,
|
||||
Some(elt) => {
|
||||
buffer.backlog.push_back(elt.clone());
|
||||
buffer.owner = !self.id;
|
||||
Some(elt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let buffer = self.rcbuffer.borrow();
|
||||
let sh = buffer.iter.size_hint();
|
||||
|
||||
if buffer.owner == self.id {
|
||||
let log_len = buffer.backlog.len();
|
||||
size_hint::add_scalar(sh, log_len)
|
||||
} else {
|
||||
sh
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> ExactSizeIterator for Tee<I>
|
||||
where I: ExactSizeIterator,
|
||||
I::Item: Clone
|
||||
{}
|
279
vendor/itertools/src/tuple_impl.rs
vendored
Normal file
279
vendor/itertools/src/tuple_impl.rs
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
//! Some iterator that produces tuples
|
||||
|
||||
use std::iter::Fuse;
|
||||
|
||||
// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
|
||||
// tuple-related methods to be used by clients in generic contexts, while
|
||||
// hiding the implementation details of `TupleCollect`.
|
||||
// See https://github.com/rust-itertools/itertools/issues/387
|
||||
|
||||
/// Implemented for homogeneous tuples of size up to 4.
|
||||
pub trait HomogeneousTuple
|
||||
: TupleCollect
|
||||
{}
|
||||
|
||||
impl<T: TupleCollect> HomogeneousTuple for T {}
|
||||
|
||||
/// An iterator over a incomplete tuple.
|
||||
///
|
||||
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) and
|
||||
/// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer).
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TupleBuffer<T>
|
||||
where T: HomogeneousTuple
|
||||
{
|
||||
cur: usize,
|
||||
buf: T::Buffer,
|
||||
}
|
||||
|
||||
impl<T> TupleBuffer<T>
|
||||
where T: HomogeneousTuple
|
||||
{
|
||||
fn new(buf: T::Buffer) -> Self {
|
||||
TupleBuffer {
|
||||
cur: 0,
|
||||
buf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterator for TupleBuffer<T>
|
||||
where T: HomogeneousTuple
|
||||
{
|
||||
type Item = T::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let s = self.buf.as_mut();
|
||||
if let Some(ref mut item) = s.get_mut(self.cur) {
|
||||
self.cur += 1;
|
||||
item.take()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let buffer = &self.buf.as_ref()[self.cur..];
|
||||
let len = if buffer.len() == 0 {
|
||||
0
|
||||
} else {
|
||||
buffer.iter()
|
||||
.position(|x| x.is_none())
|
||||
.unwrap_or(buffer.len())
|
||||
};
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ExactSizeIterator for TupleBuffer<T>
|
||||
where T: HomogeneousTuple
|
||||
{
|
||||
}
|
||||
|
||||
/// An iterator that groups the items in tuples of a specific size.
|
||||
///
|
||||
/// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information.
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct Tuples<I, T>
|
||||
where I: Iterator<Item = T::Item>,
|
||||
T: HomogeneousTuple
|
||||
{
|
||||
iter: Fuse<I>,
|
||||
buf: T::Buffer,
|
||||
}
|
||||
|
||||
/// Create a new tuples iterator.
|
||||
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
|
||||
where I: Iterator<Item = T::Item>,
|
||||
T: HomogeneousTuple
|
||||
{
|
||||
Tuples {
|
||||
iter: iter.fuse(),
|
||||
buf: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Iterator for Tuples<I, T>
|
||||
where I: Iterator<Item = T::Item>,
|
||||
T: HomogeneousTuple
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
T::collect_from_iter(&mut self.iter, &mut self.buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Tuples<I, T>
|
||||
where I: Iterator<Item = T::Item>,
|
||||
T: HomogeneousTuple
|
||||
{
|
||||
/// Return a buffer with the produced items that was not enough to be grouped in a tuple.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::Itertools;
|
||||
///
|
||||
/// let mut iter = (0..5).tuples();
|
||||
/// assert_eq!(Some((0, 1, 2)), iter.next());
|
||||
/// assert_eq!(None, iter.next());
|
||||
/// itertools::assert_equal(vec![3, 4], iter.into_buffer());
|
||||
/// ```
|
||||
pub fn into_buffer(self) -> TupleBuffer<T> {
|
||||
TupleBuffer::new(self.buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// An iterator over all contiguous windows that produces tuples of a specific size.
|
||||
///
|
||||
/// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more
|
||||
/// information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TupleWindows<I, T>
|
||||
where I: Iterator<Item = T::Item>,
|
||||
T: HomogeneousTuple
|
||||
{
|
||||
iter: I,
|
||||
last: Option<T>,
|
||||
}
|
||||
|
||||
/// Create a new tuple windows iterator.
|
||||
pub fn tuple_windows<I, T>(mut iter: I) -> TupleWindows<I, T>
|
||||
where I: Iterator<Item = T::Item>,
|
||||
T: HomogeneousTuple,
|
||||
T::Item: Clone
|
||||
{
|
||||
use std::iter::once;
|
||||
|
||||
let mut last = None;
|
||||
if T::num_items() != 1 {
|
||||
// put in a duplicate item in front of the tuple; this simplifies
|
||||
// .next() function.
|
||||
if let Some(item) = iter.next() {
|
||||
let iter = once(item.clone()).chain(once(item)).chain(&mut iter);
|
||||
last = T::collect_from_iter_no_buf(iter);
|
||||
}
|
||||
}
|
||||
|
||||
TupleWindows {
|
||||
last,
|
||||
iter,
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> Iterator for TupleWindows<I, T>
|
||||
where I: Iterator<Item = T::Item>,
|
||||
T: HomogeneousTuple + Clone,
|
||||
T::Item: Clone
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
if T::num_items() == 1 {
|
||||
return T::collect_from_iter_no_buf(&mut self.iter)
|
||||
}
|
||||
if let Some(ref mut last) = self.last {
|
||||
if let Some(new) = self.iter.next() {
|
||||
last.left_shift_push(new);
|
||||
return Some(last.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TupleCollect: Sized {
|
||||
type Item;
|
||||
type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;
|
||||
|
||||
fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
|
||||
where I: IntoIterator<Item = Self::Item>;
|
||||
|
||||
fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
|
||||
where I: IntoIterator<Item = Self::Item>;
|
||||
|
||||
fn num_items() -> usize;
|
||||
|
||||
fn left_shift_push(&mut self, item: Self::Item);
|
||||
}
|
||||
|
||||
macro_rules! impl_tuple_collect {
|
||||
() => ();
|
||||
($N:expr; $A:ident ; $($X:ident),* ; $($Y:ident),* ; $($Y_rev:ident),*) => (
|
||||
impl<$A> TupleCollect for ($($X),*,) {
|
||||
type Item = $A;
|
||||
type Buffer = [Option<$A>; $N - 1];
|
||||
|
||||
#[allow(unused_assignments, unused_mut)]
|
||||
fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
|
||||
where I: IntoIterator<Item = $A>
|
||||
{
|
||||
let mut iter = iter.into_iter();
|
||||
$(
|
||||
let mut $Y = None;
|
||||
)*
|
||||
|
||||
loop {
|
||||
$(
|
||||
$Y = iter.next();
|
||||
if $Y.is_none() {
|
||||
break
|
||||
}
|
||||
)*
|
||||
return Some(($($Y.unwrap()),*,))
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let mut s = buf.as_mut();
|
||||
$(
|
||||
if i < s.len() {
|
||||
s[i] = $Y;
|
||||
i += 1;
|
||||
}
|
||||
)*
|
||||
return None;
|
||||
}
|
||||
|
||||
#[allow(unused_assignments)]
|
||||
fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
|
||||
where I: IntoIterator<Item = $A>
|
||||
{
|
||||
let mut iter = iter.into_iter();
|
||||
loop {
|
||||
$(
|
||||
let $Y = if let Some($Y) = iter.next() {
|
||||
$Y
|
||||
} else {
|
||||
break;
|
||||
};
|
||||
)*
|
||||
return Some(($($Y),*,))
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
fn num_items() -> usize {
|
||||
$N
|
||||
}
|
||||
|
||||
fn left_shift_push(&mut self, item: $A) {
|
||||
use std::mem::replace;
|
||||
|
||||
let &mut ($(ref mut $Y),*,) = self;
|
||||
let tmp = item;
|
||||
$(
|
||||
let tmp = replace($Y_rev, tmp);
|
||||
)*
|
||||
drop(tmp);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl_tuple_collect!(1; A; A; a; a);
|
||||
impl_tuple_collect!(2; A; A, A; a, b; b, a);
|
||||
impl_tuple_collect!(3; A; A, A, A; a, b, c; c, b, a);
|
||||
impl_tuple_collect!(4; A; A, A, A, A; a, b, c, d; d, c, b, a);
|
134
vendor/itertools/src/unique_impl.rs
vendored
Normal file
134
vendor/itertools/src/unique_impl.rs
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::{Entry};
|
||||
use std::hash::Hash;
|
||||
use std::fmt;
|
||||
|
||||
/// An iterator adapter to filter out duplicate elements.
|
||||
///
|
||||
/// See [`.unique_by()`](../trait.Itertools.html#method.unique) for more information.
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct UniqueBy<I: Iterator, V, F> {
|
||||
iter: I,
|
||||
// Use a hashmap for the entry API
|
||||
used: HashMap<V, ()>,
|
||||
f: F,
|
||||
}
|
||||
|
||||
impl<I, V, F> fmt::Debug for UniqueBy<I, V, F>
|
||||
where I: Iterator + fmt::Debug,
|
||||
V: fmt::Debug + Hash + Eq,
|
||||
{
|
||||
debug_fmt_fields!(UniqueBy, iter, used);
|
||||
}
|
||||
|
||||
/// Create a new `UniqueBy` iterator.
|
||||
pub fn unique_by<I, V, F>(iter: I, f: F) -> UniqueBy<I, V, F>
|
||||
where V: Eq + Hash,
|
||||
F: FnMut(&I::Item) -> V,
|
||||
I: Iterator,
|
||||
{
|
||||
UniqueBy {
|
||||
iter,
|
||||
used: HashMap::new(),
|
||||
f,
|
||||
}
|
||||
}
|
||||
|
||||
// count the number of new unique keys in iterable (`used` is the set already seen)
|
||||
fn count_new_keys<I, K>(mut used: HashMap<K, ()>, iterable: I) -> usize
|
||||
where I: IntoIterator<Item=K>,
|
||||
K: Hash + Eq,
|
||||
{
|
||||
let iter = iterable.into_iter();
|
||||
let current_used = used.len();
|
||||
used.extend(iter.map(|key| (key, ())));
|
||||
used.len() - current_used
|
||||
}
|
||||
|
||||
impl<I, V, F> Iterator for UniqueBy<I, V, F>
|
||||
where I: Iterator,
|
||||
V: Eq + Hash,
|
||||
F: FnMut(&I::Item) -> V
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
while let Some(v) = self.iter.next() {
|
||||
let key = (self.f)(&v);
|
||||
if self.used.insert(key, ()).is_none() {
|
||||
return Some(v);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (low, hi) = self.iter.size_hint();
|
||||
((low > 0 && self.used.is_empty()) as usize, hi)
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
let mut key_f = self.f;
|
||||
count_new_keys(self.used, self.iter.map(move |elt| key_f(&elt)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> Iterator for Unique<I>
|
||||
where I: Iterator,
|
||||
I::Item: Eq + Hash + Clone
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
while let Some(v) = self.iter.iter.next() {
|
||||
if let Entry::Vacant(entry) = self.iter.used.entry(v) {
|
||||
let elt = entry.key().clone();
|
||||
entry.insert(());
|
||||
return Some(elt);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (low, hi) = self.iter.iter.size_hint();
|
||||
((low > 0 && self.iter.used.is_empty()) as usize, hi)
|
||||
}
|
||||
|
||||
fn count(self) -> usize {
|
||||
count_new_keys(self.iter.used, self.iter.iter)
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator adapter to filter out duplicate elements.
|
||||
///
|
||||
/// See [`.unique()`](../trait.Itertools.html#method.unique) for more information.
|
||||
#[derive(Clone)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct Unique<I: Iterator> {
|
||||
iter: UniqueBy<I, I::Item, ()>,
|
||||
}
|
||||
|
||||
impl<I> fmt::Debug for Unique<I>
|
||||
where I: Iterator + fmt::Debug,
|
||||
I::Item: Hash + Eq + fmt::Debug,
|
||||
{
|
||||
debug_fmt_fields!(Unique, iter);
|
||||
}
|
||||
|
||||
pub fn unique<I>(iter: I) -> Unique<I>
|
||||
where I: Iterator,
|
||||
I::Item: Eq + Hash,
|
||||
{
|
||||
Unique {
|
||||
iter: UniqueBy {
|
||||
iter,
|
||||
used: HashMap::new(),
|
||||
f: (),
|
||||
}
|
||||
}
|
||||
}
|
97
vendor/itertools/src/with_position.rs
vendored
Normal file
97
vendor/itertools/src/with_position.rs
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
use std::iter::{Fuse,Peekable};
|
||||
|
||||
/// An iterator adaptor that wraps each element in an [`Position`](../enum.Position.html).
|
||||
///
|
||||
/// Iterator element type is `Position<I::Item>`.
|
||||
///
|
||||
/// See [`.with_position()`](../trait.Itertools.html#method.with_position) for more information.
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct WithPosition<I>
|
||||
where I: Iterator,
|
||||
{
|
||||
handled_first: bool,
|
||||
peekable: Peekable<Fuse<I>>,
|
||||
}
|
||||
|
||||
impl<I> Clone for WithPosition<I>
|
||||
where I: Clone + Iterator,
|
||||
I::Item: Clone,
|
||||
{
|
||||
clone_fields!(handled_first, peekable);
|
||||
}
|
||||
|
||||
/// Create a new `WithPosition` iterator.
|
||||
pub fn with_position<I>(iter: I) -> WithPosition<I>
|
||||
where I: Iterator,
|
||||
{
|
||||
WithPosition {
|
||||
handled_first: false,
|
||||
peekable: iter.fuse().peekable(),
|
||||
}
|
||||
}
|
||||
|
||||
/// A value yielded by `WithPosition`.
|
||||
/// Indicates the position of this element in the iterator results.
|
||||
///
|
||||
/// See [`.with_position()`](trait.Itertools.html#method.with_position) for more information.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Position<T> {
|
||||
/// This is the first element.
|
||||
First(T),
|
||||
/// This is neither the first nor the last element.
|
||||
Middle(T),
|
||||
/// This is the last element.
|
||||
Last(T),
|
||||
/// This is the only element.
|
||||
Only(T),
|
||||
}
|
||||
|
||||
impl<T> Position<T> {
|
||||
/// Return the inner value.
|
||||
pub fn into_inner(self) -> T {
|
||||
match self {
|
||||
Position::First(x) |
|
||||
Position::Middle(x) |
|
||||
Position::Last(x) |
|
||||
Position::Only(x) => x,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator> Iterator for WithPosition<I> {
|
||||
type Item = Position<I::Item>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.peekable.next() {
|
||||
Some(item) => {
|
||||
if !self.handled_first {
|
||||
// Haven't seen the first item yet, and there is one to give.
|
||||
self.handled_first = true;
|
||||
// Peek to see if this is also the last item,
|
||||
// in which case tag it as `Only`.
|
||||
match self.peekable.peek() {
|
||||
Some(_) => Some(Position::First(item)),
|
||||
None => Some(Position::Only(item)),
|
||||
}
|
||||
} else {
|
||||
// Have seen the first item, and there's something left.
|
||||
// Peek to see if this is the last item.
|
||||
match self.peekable.peek() {
|
||||
Some(_) => Some(Position::Middle(item)),
|
||||
None => Some(Position::Last(item)),
|
||||
}
|
||||
}
|
||||
}
|
||||
// Iterator is finished.
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.peekable.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> ExactSizeIterator for WithPosition<I>
|
||||
where I: ExactSizeIterator,
|
||||
{ }
|
60
vendor/itertools/src/zip_eq_impl.rs
vendored
Normal file
60
vendor/itertools/src/zip_eq_impl.rs
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
use super::size_hint;
|
||||
|
||||
/// An iterator which iterates two other iterators simultaneously
|
||||
///
|
||||
/// See [`.zip_eq()`](../trait.Itertools.html#method.zip_eq) for more information.
|
||||
#[derive(Clone, Debug)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct ZipEq<I, J> {
|
||||
a: I,
|
||||
b: J,
|
||||
}
|
||||
|
||||
/// Iterate `i` and `j` in lock step.
|
||||
///
|
||||
/// **Panics** if the iterators are not of the same length.
|
||||
///
|
||||
/// `IntoIterator` enabled version of `i.zip_eq(j)`.
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::zip_eq;
|
||||
///
|
||||
/// let data = [1, 2, 3, 4, 5];
|
||||
/// for (a, b) in zip_eq(&data[..data.len() - 1], &data[1..]) {
|
||||
/// /* loop body */
|
||||
/// }
|
||||
/// ```
|
||||
pub fn zip_eq<I, J>(i: I, j: J) -> ZipEq<I::IntoIter, J::IntoIter>
|
||||
where I: IntoIterator,
|
||||
J: IntoIterator
|
||||
{
|
||||
ZipEq {
|
||||
a: i.into_iter(),
|
||||
b: j.into_iter(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, J> Iterator for ZipEq<I, J>
|
||||
where I: Iterator,
|
||||
J: Iterator
|
||||
{
|
||||
type Item = (I::Item, J::Item);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match (self.a.next(), self.b.next()) {
|
||||
(None, None) => None,
|
||||
(Some(a), Some(b)) => Some((a, b)),
|
||||
(None, Some(_)) | (Some(_), None) =>
|
||||
panic!("itertools: .zip_eq() reached end of one iterator before the other")
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
size_hint::min(self.a.size_hint(), self.b.size_hint())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, J> ExactSizeIterator for ZipEq<I, J>
|
||||
where I: ExactSizeIterator,
|
||||
J: ExactSizeIterator
|
||||
{}
|
78
vendor/itertools/src/zip_longest.rs
vendored
Normal file
78
vendor/itertools/src/zip_longest.rs
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||
use super::size_hint;
|
||||
use std::iter::Fuse;
|
||||
|
||||
use crate::either_or_both::EitherOrBoth;
|
||||
|
||||
// ZipLongest originally written by SimonSapin,
|
||||
// and dedicated to itertools https://github.com/rust-lang/rust/pull/19283
|
||||
|
||||
/// An iterator which iterates two other iterators simultaneously
|
||||
///
|
||||
/// This iterator is *fused*.
|
||||
///
|
||||
/// See [`.zip_longest()`](../trait.Itertools.html#method.zip_longest) for more information.
|
||||
#[derive(Clone, Debug)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct ZipLongest<T, U> {
|
||||
a: Fuse<T>,
|
||||
b: Fuse<U>,
|
||||
}
|
||||
|
||||
/// Create a new `ZipLongest` iterator.
|
||||
pub fn zip_longest<T, U>(a: T, b: U) -> ZipLongest<T, U>
|
||||
where T: Iterator,
|
||||
U: Iterator
|
||||
{
|
||||
ZipLongest {
|
||||
a: a.fuse(),
|
||||
b: b.fuse(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Iterator for ZipLongest<T, U>
|
||||
where T: Iterator,
|
||||
U: Iterator
|
||||
{
|
||||
type Item = EitherOrBoth<T::Item, U::Item>;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match (self.a.next(), self.b.next()) {
|
||||
(None, None) => None,
|
||||
(Some(a), None) => Some(EitherOrBoth::Left(a)),
|
||||
(None, Some(b)) => Some(EitherOrBoth::Right(b)),
|
||||
(Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
size_hint::max(self.a.size_hint(), self.b.size_hint())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> DoubleEndedIterator for ZipLongest<T, U>
|
||||
where T: DoubleEndedIterator + ExactSizeIterator,
|
||||
U: DoubleEndedIterator + ExactSizeIterator
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
match self.a.len().cmp(&self.b.len()) {
|
||||
Equal => match (self.a.next_back(), self.b.next_back()) {
|
||||
(None, None) => None,
|
||||
(Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)),
|
||||
// These can only happen if .len() is inconsistent with .next_back()
|
||||
(Some(a), None) => Some(EitherOrBoth::Left(a)),
|
||||
(None, Some(b)) => Some(EitherOrBoth::Right(b)),
|
||||
},
|
||||
Greater => self.a.next_back().map(EitherOrBoth::Left),
|
||||
Less => self.b.next_back().map(EitherOrBoth::Right),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ExactSizeIterator for ZipLongest<T, U>
|
||||
where T: ExactSizeIterator,
|
||||
U: ExactSizeIterator
|
||||
{}
|
111
vendor/itertools/src/ziptuple.rs
vendored
Normal file
111
vendor/itertools/src/ziptuple.rs
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
use super::size_hint;
|
||||
|
||||
/// See [`multizip`](../fn.multizip.html) for more information.
|
||||
#[derive(Clone, Debug)]
|
||||
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
|
||||
pub struct Zip<T> {
|
||||
t: T,
|
||||
}
|
||||
|
||||
/// An iterator that generalizes *.zip()* and allows running multiple iterators in lockstep.
|
||||
///
|
||||
/// The iterator `Zip<(I, J, ..., M)>` is formed from a tuple of iterators (or values that
|
||||
/// implement `IntoIterator`) and yields elements
|
||||
/// until any of the subiterators yields `None`.
|
||||
///
|
||||
/// The iterator element type is a tuple like like `(A, B, ..., E)` where `A` to `E` are the
|
||||
/// element types of the subiterator.
|
||||
///
|
||||
/// **Note:** The result of this macro is a value of a named type (`Zip<(I, J,
|
||||
/// ..)>` of each component iterator `I, J, ...`) if each component iterator is
|
||||
/// nameable.
|
||||
///
|
||||
/// Prefer [`izip!()`] over `multizip` for the performance benefits of using the
|
||||
/// standard library `.zip()`. Prefer `multizip` if a nameable type is needed.
|
||||
///
|
||||
/// [`izip!()`]: macro.izip.html
|
||||
///
|
||||
/// ```
|
||||
/// use itertools::multizip;
|
||||
///
|
||||
/// // iterate over three sequences side-by-side
|
||||
/// let mut results = [0, 0, 0, 0];
|
||||
/// let inputs = [3, 7, 9, 6];
|
||||
///
|
||||
/// for (r, index, input) in multizip((&mut results, 0..10, &inputs)) {
|
||||
/// *r = index * 10 + input;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]);
|
||||
/// ```
|
||||
pub fn multizip<T, U>(t: U) -> Zip<T>
|
||||
where Zip<T>: From<U>,
|
||||
Zip<T>: Iterator,
|
||||
{
|
||||
Zip::from(t)
|
||||
}
|
||||
|
||||
macro_rules! impl_zip_iter {
|
||||
($($B:ident),*) => (
|
||||
#[allow(non_snake_case)]
|
||||
impl<$($B: IntoIterator),*> From<($($B,)*)> for Zip<($($B::IntoIter,)*)> {
|
||||
fn from(t: ($($B,)*)) -> Self {
|
||||
let ($($B,)*) = t;
|
||||
Zip { t: ($($B.into_iter(),)*) }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(unused_assignments)]
|
||||
impl<$($B),*> Iterator for Zip<($($B,)*)>
|
||||
where
|
||||
$(
|
||||
$B: Iterator,
|
||||
)*
|
||||
{
|
||||
type Item = ($($B::Item,)*);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
let ($(ref mut $B,)*) = self.t;
|
||||
|
||||
// NOTE: Just like iter::Zip, we check the iterators
|
||||
// for None in order. We may finish unevenly (some
|
||||
// iterators gave n + 1 elements, some only n).
|
||||
$(
|
||||
let $B = match $B.next() {
|
||||
None => return None,
|
||||
Some(elt) => elt
|
||||
};
|
||||
)*
|
||||
Some(($($B,)*))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>)
|
||||
{
|
||||
let sh = (::std::usize::MAX, None);
|
||||
let ($(ref $B,)*) = self.t;
|
||||
$(
|
||||
let sh = size_hint::min($B.size_hint(), sh);
|
||||
)*
|
||||
sh
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl<$($B),*> ExactSizeIterator for Zip<($($B,)*)> where
|
||||
$(
|
||||
$B: ExactSizeIterator,
|
||||
)*
|
||||
{ }
|
||||
);
|
||||
}
|
||||
|
||||
impl_zip_iter!(A);
|
||||
impl_zip_iter!(A, B);
|
||||
impl_zip_iter!(A, B, C);
|
||||
impl_zip_iter!(A, B, C, D);
|
||||
impl_zip_iter!(A, B, C, D, E);
|
||||
impl_zip_iter!(A, B, C, D, E, F);
|
||||
impl_zip_iter!(A, B, C, D, E, F, G);
|
||||
impl_zip_iter!(A, B, C, D, E, F, G, H);
|
47
vendor/itertools/tests/adaptors_no_collect.rs
vendored
Normal file
47
vendor/itertools/tests/adaptors_no_collect.rs
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
use itertools::Itertools;
|
||||
|
||||
struct PanickingCounter {
|
||||
curr: usize,
|
||||
max: usize,
|
||||
}
|
||||
|
||||
impl Iterator for PanickingCounter {
|
||||
type Item = ();
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.curr += 1;
|
||||
|
||||
if self.curr == self.max {
|
||||
panic!(
|
||||
"Input iterator reached maximum of {} suggesting collection by adaptor",
|
||||
self.max
|
||||
);
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
fn no_collect_test<A, T>(to_adaptor: T)
|
||||
where A: Iterator, T: Fn(PanickingCounter) -> A
|
||||
{
|
||||
let counter = PanickingCounter { curr: 0, max: 10_000 };
|
||||
let adaptor = to_adaptor(counter);
|
||||
|
||||
for _ in adaptor.take(5) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permutations_no_collect() {
|
||||
no_collect_test(|iter| iter.permutations(5))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn combinations_no_collect() {
|
||||
no_collect_test(|iter| iter.combinations(5))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn combinations_with_replacement_no_collect() {
|
||||
no_collect_test(|iter| iter.combinations_with_replacement(5))
|
||||
}
|
13
vendor/itertools/tests/fold_specialization.rs
vendored
Normal file
13
vendor/itertools/tests/fold_specialization.rs
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
use itertools::Itertools;
|
||||
|
||||
#[test]
|
||||
fn specialization_intersperse() {
|
||||
let mut iter = (1..2).intersperse(0);
|
||||
iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
|
||||
|
||||
let mut iter = (1..3).intersperse(0);
|
||||
iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
|
||||
|
||||
let mut iter = (1..4).intersperse(0);
|
||||
iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user