diff --git a/.ci/ci b/.ci/ci index f1995e7de..6065d7fe3 100755 --- a/.ci/ci +++ b/.ci/ci @@ -23,6 +23,10 @@ make prepare-tidy make -j8 unit-test make -j8 run-unit-tests make -j8 run-rust-unit-tests + +# Rust linter +make -j8 run-rust-clippy + # Check that coverage report building is working. make coverage diff --git a/messages/CMakeLists.txt b/messages/CMakeLists.txt index d0abfa1ca..e7bb112d6 100644 --- a/messages/CMakeLists.txt +++ b/messages/CMakeLists.txt @@ -51,6 +51,13 @@ add_custom_command( --proto_path=${CMAKE_CURRENT_SOURCE_DIR} '--nanopb_out=-I${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_CURRENT_BINARY_DIR}' ${PROTO_FILES_ABSOLUTE} + # We build the Rust protobuf files here and put them straight into the crate. + # This way, the crate can be compiled and tested without relying on cmake environment vars. + # Using prost-build the normal way as part of build.rs does not work due to a cargo bug: + # https://github.com/danburkert/prost/issues/344#issuecomment-650721245 + COMMAND + ${CMAKE_COMMAND} -E env + cargo run --manifest-path=${CMAKE_SOURCE_DIR}/tools/prost-build/Cargo.toml -- --messages-dir=${CMAKE_CURRENT_SOURCE_DIR} --out-dir=${CMAKE_SOURCE_DIR}/src/rust/bitbox02-rust/src/hww/api/ ) add_custom_target( diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc812ac9a..edceac7b3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -373,6 +373,8 @@ add_custom_target(rust-bindgen --whitelist-type commander_error_t --rustified-enum commander_error_t --whitelist-function commander + --whitelist-function commander_states_can_call + --whitelist-function commander_states_clear_force_next --whitelist-type BitBoxBaseRequest --whitelist-var ".*_tag" --whitelist-var MAX_LABEL_SIZE diff --git a/src/commander/commander.c b/src/commander/commander.c index 7c6dc7bc7..44868d401 100644 --- a/src/commander/commander.c +++ b/src/commander/commander.c @@ -123,22 +123,6 @@ static commander_error_t _api_get_info(DeviceInfoResponse* device_info) return COMMANDER_OK; } -static commander_error_t _api_set_device_name(const SetDeviceNameRequest* request) -{ - const confirm_params_t params = { - .title = "Name", - .body = request->name, - .scrollable = true, - }; - if (!workflow_confirm_blocking(¶ms)) { - return COMMANDER_ERR_USER_ABORT; - } - if (!memory_set_device_name(request->name)) { - return COMMANDER_ERR_MEMORY; - } - return COMMANDER_OK; -} - static commander_error_t _api_set_password(const SetPasswordRequest* request) { if (!workflow_create_seed(request->entropy)) { @@ -282,9 +266,6 @@ static commander_error_t _api_process(const Request* request, Response* response case Request_device_info_tag: response->which_response = Response_device_info_tag; return _api_get_info(&(response->response.device_info)); - case Request_device_name_tag: - response->which_response = Response_success_tag; - return _api_set_device_name(&(request->request.device_name)); case Request_set_password_tag: response->which_response = Response_success_tag; return _api_set_password(&(request->request.set_password)); @@ -381,17 +362,8 @@ void commander(const in_buffer_t* in_buf, buffer_t* out_buf) commander_error_t err = protobuf_decode(in_buf, &request) ? COMMANDER_OK : COMMANDER_ERR_INVALID_INPUT; if (err == COMMANDER_OK) { - if (!commander_states_can_call(request.which_request)) { - err = COMMANDER_ERR_INVALID_STATE; - } else { - // Since we will process the call now, so can clear the 'force next' info. - // We do this before processing as the api call can potentially define the next api call - // to be forced. - commander_states_clear_force_next(); - - err = _api_process(&request, &response); - util_zero(&request, sizeof(request)); - } + err = _api_process(&request, &response); + util_zero(&request, sizeof(request)); } if (err != COMMANDER_OK) { _report_error(&response, err); @@ -401,10 +373,6 @@ void commander(const in_buffer_t* in_buf, buffer_t* out_buf) } #ifdef TESTING -commander_error_t commander_api_set_device_name(const SetDeviceNameRequest* request) -{ - return _api_set_device_name(request); -} commander_error_t commander_api_set_mnemonic_passphrase_enabled( const SetMnemonicPassphraseEnabledRequest* request) { diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 0879d3697..3a2e9b062 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -8,6 +8,11 @@ dependencies = [ "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "anyhow" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayref" version = "0.3.6" @@ -50,6 +55,7 @@ dependencies = [ "binascii 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitbox02 0.1.0", "bitbox02-noise 0.1.0", + "prost 0.6.1 (git+https://github.com/danburkert/prost.git?rev=6113789f70b69709820becba4242824b4fb3ffec)", ] [[package]] @@ -102,6 +108,11 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytes" +version = "0.5.5" +source = "git+https://github.com/digitalbitbox/bytes.git?branch=bitbox02-firmware-20200702#0c63de95b05927ef40ad13e6d1055e3f97f94613" + [[package]] name = "chacha20" version = "0.3.4" @@ -143,6 +154,11 @@ dependencies = [ "generic-array 0.12.3 (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 = "ethereum" version = "0.1.0" @@ -171,6 +187,14 @@ name = "hex" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "itertools" +version = "0.9.0" +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 = "keccak" version = "0.1.0" @@ -216,6 +240,27 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "prost" +version = "0.6.1" +source = "git+https://github.com/danburkert/prost.git?rev=6113789f70b69709820becba4242824b4fb3ffec#6113789f70b69709820becba4242824b4fb3ffec" +dependencies = [ + "bytes 0.5.5 (git+https://github.com/digitalbitbox/bytes.git?branch=bitbox02-firmware-20200702)", + "prost-derive 0.6.1 (git+https://github.com/danburkert/prost.git?rev=6113789f70b69709820becba4242824b4fb3ffec)", +] + +[[package]] +name = "prost-derive" +version = "0.6.1" +source = "git+https://github.com/danburkert/prost.git?rev=6113789f70b69709820becba4242824b4fb3ffec#6113789f70b69709820becba4242824b4fb3ffec" +dependencies = [ + "anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "1.0.3" @@ -340,6 +385,7 @@ dependencies = [ [metadata] "checksum aead 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4cf01b9b56e767bb57b94ebf91a58b338002963785cdd7013e21c0d4679471e4" +"checksum anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" "checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum binascii 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" @@ -347,19 +393,24 @@ dependencies = [ "checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +"checksum bytes 0.5.5 (git+https://github.com/digitalbitbox/bytes.git?branch=bitbox02-firmware-20200702)" = "" "checksum chacha20 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f6a7ae4c498f8447d86baef0fa0831909333f558866fabcb21600625ac5a31c7" "checksum chacha20poly1305 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "48901293601228db2131606f741db33561f7576b5d19c99cd66222380a7dc863" "checksum curve25519-dalek 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" +"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum noise-protocol 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5ecc9fd83ab18487621c3cd1b7185721ed2f0cdeb4a35c6b4d44f87988a6ff24" "checksum noise-rust-crypto 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "374ccd1adc6a1207e60a061d98284715bde21bf58f25b2cb69ed89f2f9d7cdc8" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum poly1305 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5829f50f48e9ddb79f3f7c3097029d0caee30f8286accb241416df603b080b8" "checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +"checksum prost 0.6.1 (git+https://github.com/danburkert/prost.git?rev=6113789f70b69709820becba4242824b4fb3ffec)" = "" +"checksum prost-derive 0.6.1 (git+https://github.com/danburkert/prost.git?rev=6113789f70b69709820becba4242824b4fb3ffec)" = "" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 20903e363..36ff6362d 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -33,3 +33,6 @@ lto = true [profile.dev] opt-level = 'z' + +[patch.crates-io] +bytes = { git = "https://github.com/digitalbitbox/bytes.git", branch = "bitbox02-firmware-20200702" } diff --git a/src/rust/bitbox02-rust-c/src/util.rs b/src/rust/bitbox02-rust-c/src/util.rs index 17d2b071e..8ada570c2 100644 --- a/src/rust/bitbox02-rust-c/src/util.rs +++ b/src/rust/bitbox02-rust-c/src/util.rs @@ -189,7 +189,7 @@ impl CStrMut { /// then are available. pub fn write(&mut self, req: usize, f: F) where - F: FnOnce(&mut [u8]) -> (), + F: FnOnce(&mut [u8]), { // Must be room for requested amount of bytes and null terminator. if self.cap - self.len < req + 1 { diff --git a/src/rust/bitbox02-rust-c/src/workflow.rs b/src/rust/bitbox02-rust-c/src/workflow.rs index b2119c98c..d0afbc60c 100644 --- a/src/rust/bitbox02-rust-c/src/workflow.rs +++ b/src/rust/bitbox02-rust-c/src/workflow.rs @@ -155,7 +155,7 @@ pub unsafe extern "C" fn rust_workflow_confirm_blocking( ) -> bool { let title = crate::util::rust_util_cstr(params.title); let body = crate::util::rust_util_cstr(params.body); - if params.font != core::ptr::null() { + if !params.font.is_null() { panic!("Only default font supported"); } let params = confirm::Params { diff --git a/src/rust/bitbox02-rust/Cargo.toml b/src/rust/bitbox02-rust/Cargo.toml index f6cbdad0c..9ea1ab03d 100644 --- a/src/rust/bitbox02-rust/Cargo.toml +++ b/src/rust/bitbox02-rust/Cargo.toml @@ -35,3 +35,10 @@ bitbox02-noise = {path = "../bitbox02-noise"} version = "0.5.1" # Disable the "std" feature default-features = false + +[dependencies.prost] +git = "https://github.com/danburkert/prost.git" +# keep rev in sync with tools/prost-build/Cargo.toml +rev = "6113789f70b69709820becba4242824b4fb3ffec" +default-features = false +features = ["prost-derive"] diff --git a/src/rust/bitbox02-rust/src/hww/api/mod.rs b/src/rust/bitbox02-rust/src/hww/api/mod.rs new file mode 100644 index 000000000..493b19fc4 --- /dev/null +++ b/src/rust/bitbox02-rust/src/hww/api/mod.rs @@ -0,0 +1,168 @@ +// Copyright 2020 Shift Crypto AG +// +// 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. + +mod pb { + include!("./shiftcrypto.bitbox02.rs"); +} + +use alloc::vec::Vec; + +use bitbox02::commander::Error; +use pb::request::Request; +use pb::response::Response; +use prost::Message; + +/// Creates an Error response. Corresponds to commander.c:_report_error(). +fn make_error(err: bitbox02::commander::Error) -> Response { + use Error::*; + let err = match err { + COMMANDER_OK => panic!("can't call this function with COMMANDER_OK"), + COMMANDER_ERR_INVALID_INPUT => pb::Error { + code: 101, + message: "invalid input".into(), + }, + COMMANDER_ERR_MEMORY => pb::Error { + code: 102, + message: "memory".into(), + }, + COMMANDER_ERR_GENERIC => pb::Error { + code: 103, + message: "generic error".into(), + }, + COMMANDER_ERR_USER_ABORT => pb::Error { + code: 104, + message: "aborted by the user".into(), + }, + COMMANDER_ERR_INVALID_STATE => pb::Error { + code: 105, + message: "can't call this endpoint: wrong state".into(), + }, + COMMANDER_ERR_DISABLED => pb::Error { + code: 106, + message: "function disabled".into(), + }, + COMMANDER_ERR_DUPLICATE => pb::Error { + code: 107, + message: "duplicate entry".into(), + }, + }; + Response::Error(err) +} + +/// Encodes a protobuf Response message. +fn encode(response: Response) -> Vec { + let response = pb::Response { + response: Some(response), + }; + let mut out = Vec::::new(); + response.encode(&mut out).unwrap(); + out +} + +/// Returns the field tag number of the request as defined in the .proto file. This is needed for +/// compatibility with commander_states.c, and needed as long as API calls processed in C use +/// `commmander_states_force_next()`. +fn request_tag(request: &Request) -> u32 { + use Request::*; + match request { + RandomNumber(_) => bitbox02::Request_random_number_tag, + DeviceName(_) => bitbox02::Request_device_name_tag, + DeviceLanguage(_) => bitbox02::Request_device_language_tag, + DeviceInfo(_) => bitbox02::Request_device_info_tag, + SetPassword(_) => bitbox02::Request_set_password_tag, + CreateBackup(_) => bitbox02::Request_create_backup_tag, + ShowMnemonic(_) => bitbox02::Request_show_mnemonic_tag, + BtcPub(_) => bitbox02::Request_btc_pub_tag, + BtcSignInit(_) => bitbox02::Request_btc_sign_init_tag, + BtcSignInput(_) => bitbox02::Request_btc_sign_input_tag, + BtcSignOutput(_) => bitbox02::Request_btc_sign_output_tag, + InsertRemoveSdcard(_) => bitbox02::Request_insert_remove_sdcard_tag, + CheckSdcard(_) => bitbox02::Request_check_sdcard_tag, + SetMnemonicPassphraseEnabled(_) => bitbox02::Request_set_mnemonic_passphrase_enabled_tag, + ListBackups(_) => bitbox02::Request_list_backups_tag, + RestoreBackup(_) => bitbox02::Request_restore_backup_tag, + PerformAttestation(_) => bitbox02::Request_perform_attestation_tag, + Reboot(_) => bitbox02::Request_reboot_tag, + CheckBackup(_) => bitbox02::Request_check_backup_tag, + Eth(_) => bitbox02::Request_eth_tag, + Reset(_) => bitbox02::Request_reset_tag, + RestoreFromMnemonic(_) => bitbox02::Request_restore_from_mnemonic_tag, + Bitboxbase(_) => bitbox02::Request_bitboxbase_tag, + Fingerprint(_) => bitbox02::Request_fingerprint_tag, + Btc(_) => bitbox02::Request_btc_tag, + ElectrumEncryptionKey(_) => bitbox02::Request_electrum_encryption_key_tag, + } +} + +async fn api_set_device_name( + pb::SetDeviceNameRequest { name }: &pb::SetDeviceNameRequest, +) -> Response { + use crate::workflow::confirm; + let params = confirm::Params { + title: "Name", + body: &name, + scrollable: true, + ..Default::default() + }; + + if !confirm::confirm(¶ms).await { + return make_error(Error::COMMANDER_ERR_USER_ABORT); + } + + if bitbox02::memory::set_device_name(&name).is_err() { + return make_error(Error::COMMANDER_ERR_MEMORY); + } + + Response::Success(pb::Success {}) +} + +/// Handle a protobuf api call. +/// +/// Returns `None` if the call was not handled by Rust, in which case +/// it should be handled by the C commander. +async fn process_api(request: &Request) -> Option { + match request { + Request::DeviceName(ref request) => Some(api_set_device_name(request).await), + _ => None, + } +} + +/// Handle a protobuf api call. API calls not handled by Rust are +/// handled by the C commander, which allows us to use Rust for new +/// api calls and port the old calls step by step. +/// +/// `input` is a hww.proto Request message, protobuf encoded. +/// Returns a protobuf encoded hww.proto Response message. +pub async fn process(input: Vec) -> Vec { + let request = match pb::Request::decode(&input[..]) { + Ok(pb::Request { + request: Some(request), + }) => request, + _ => return encode(make_error(Error::COMMANDER_ERR_INVALID_INPUT)), + }; + if !bitbox02::commander::states_can_call(request_tag(&request) as u16) { + return encode(make_error(Error::COMMANDER_ERR_INVALID_STATE)); + } + + // Since we will process the call now, so can clear the 'force next' info. + // We do this before processing as the api call can potentially define the next api call + // to be forced. + bitbox02::commander::states_clear_force_next(); + + match process_api(&request).await { + Some(response) => encode(response), + // Api call not handled in Rust -> handle it in C. + _ => bitbox02::commander::commander(input), + } +} diff --git a/src/rust/bitbox02-rust/src/hww/api/shiftcrypto.bitbox02.rs b/src/rust/bitbox02-rust/src/hww/api/shiftcrypto.bitbox02.rs new file mode 100644 index 000000000..43dbed4ca --- /dev/null +++ b/src/rust/bitbox02-rust/src/hww/api/shiftcrypto.bitbox02.rs @@ -0,0 +1,793 @@ +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PubResponse { + #[prost(string, tag="1")] + pub r#pub: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RootFingerprintRequest { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RootFingerprintResponse { + #[prost(bytes, tag="1")] + pub fingerprint: ::prost::alloc::vec::Vec, +} +/// See https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki. +/// version field dropped as it will set dynamically based on the context (xpub, ypub, etc.). +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct XPub { + #[prost(bytes, tag="1")] + pub depth: ::prost::alloc::vec::Vec, + #[prost(bytes, tag="2")] + pub parent_fingerprint: ::prost::alloc::vec::Vec, + #[prost(uint32, tag="3")] + pub child_num: u32, + #[prost(bytes, tag="4")] + pub chain_code: ::prost::alloc::vec::Vec, + #[prost(bytes, tag="5")] + pub public_key: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CheckBackupRequest { + #[prost(bool, tag="1")] + pub silent: bool, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CheckBackupResponse { + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, +} +/// Timestamp must be in UTC +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateBackupRequest { + #[prost(uint32, tag="1")] + pub timestamp: u32, + #[prost(int32, tag="2")] + pub timezone_offset: i32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListBackupsRequest { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BackupInfo { + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub timestamp: u32, + /// uint32 timezone_offset = 3; + #[prost(string, tag="4")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListBackupsResponse { + #[prost(message, repeated, tag="1")] + pub info: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RestoreBackupRequest { + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub timestamp: u32, + #[prost(int32, tag="3")] + pub timezone_offset: i32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CheckSdCardRequest { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CheckSdCardResponse { + #[prost(bool, tag="1")] + pub inserted: bool, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeviceInfoRequest { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DeviceInfoResponse { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(bool, tag="2")] + pub initialized: bool, + #[prost(string, tag="3")] + pub version: ::prost::alloc::string::String, + #[prost(bool, tag="4")] + pub mnemonic_passphrase_enabled: bool, + #[prost(uint32, tag="5")] + pub monotonic_increments_remaining: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InsertRemoveSdCardRequest { + #[prost(enumeration="insert_remove_sd_card_request::SdCardAction", tag="1")] + pub action: i32, +} +/// Nested message and enum types in `InsertRemoveSDCardRequest`. +pub mod insert_remove_sd_card_request { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum SdCardAction { + RemoveCard = 0, + InsertCard = 1, + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ResetRequest { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SetDeviceLanguageRequest { + #[prost(string, tag="1")] + pub language: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SetDeviceNameRequest { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SetPasswordRequest { + #[prost(bytes, tag="1")] + pub entropy: ::prost::alloc::vec::Vec, +} +/// Should be sent every X seconds (TBD) unless the firmware already is busy with a command. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BitBoxBaseHeartbeatRequest { + #[prost(enumeration="bit_box_base_heartbeat_request::StateCode", tag="1")] + pub state_code: i32, + #[prost(enumeration="bit_box_base_heartbeat_request::DescriptionCode", tag="2")] + pub description_code: i32, +} +/// Nested message and enum types in `BitBoxBaseHeartbeatRequest`. +pub mod bit_box_base_heartbeat_request { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum StateCode { + Idle = 0, + Working = 1, + Warning = 2, + Error = 3, + } + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum DescriptionCode { + Empty = 0, + InitialBlockSync = 1, + DownloadUpdate = 2, + OutOfDiskSpace = 3, + RedisError = 4, + Reboot = 5, + Shutdown = 6, + UpdateFailed = 7, + NoNetworkConnection = 8, + } +} +/// This will display the first 20 characters of the base32 encoded version of +/// the provided msg +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BitBoxBaseConfirmPairingRequest { + #[prost(bytes, tag="1")] + pub msg: ::prost::alloc::vec::Vec, +} +/// Optional fields can be represented by a "oneof" with only one field in it. +/// All fields are technically optional. But in reality the default value for the type will be set. +/// It is therefore impossible to distinguish between the default value and if the value wasn't set. +/// So any fields that have a default value which also is a valid value can use this method to send +/// an empty value. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BitBoxBaseSetConfigRequest { + #[prost(enumeration="bit_box_base_set_config_request::StatusLedMode", tag="1")] + pub status_led_mode: i32, + #[prost(enumeration="bit_box_base_set_config_request::StatusScreenMode", tag="2")] + pub status_screen_mode: i32, + /// Empty string means unsetting the hostname + #[prost(string, tag="4")] + pub hostname: ::prost::alloc::string::String, + /// 0.0.0.0 which is the default value of ip is also a valid IP, use the oneof-trick to determine + /// if IP wasn't set in the message. + #[prost(oneof="bit_box_base_set_config_request::IpOption", tags="3")] + pub ip_option: ::core::option::Option, +} +/// Nested message and enum types in `BitBoxBaseSetConfigRequest`. +pub mod bit_box_base_set_config_request { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum StatusLedMode { + /// display on led when status is IDLE, WORKING, WARNING and ERROR + LedAlways = 0, + /// display on led when status is WORKING, WARNING and ERROR + LedOnWorking = 1, + /// display on led when status is WARNING and ERROR + LedOnWarning = 2, + /// display on led when status is ERROR + LedOnError = 3, + } + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum StatusScreenMode { + /// display on screen when status is IDLE, WORKING, WARNING and ERROR + ScreenAlways = 0, + /// display on screen when status is WORKING, WARNING and ERROR + ScreenOnWorking = 1, + /// display on screen when status is WARNING and ERROR + ScreenOnWarning = 2, + /// display on screen when status is ERROR + ScreenOnError = 3, + } + /// 0.0.0.0 which is the default value of ip is also a valid IP, use the oneof-trick to determine + /// if IP wasn't set in the message. + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum IpOption { + #[prost(bytes, tag="3")] + Ip(::prost::alloc::vec::Vec), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BitBoxBaseDisplayStatusRequest { + #[prost(uint32, tag="1")] + pub duration: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BitBoxBaseRequest { + #[prost(oneof="bit_box_base_request::Request", tags="1, 2, 3, 4")] + pub request: ::core::option::Option, +} +/// Nested message and enum types in `BitBoxBaseRequest`. +pub mod bit_box_base_request { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Request { + #[prost(message, tag="1")] + Heartbeat(super::BitBoxBaseHeartbeatRequest), + #[prost(message, tag="2")] + SetConfig(super::BitBoxBaseSetConfigRequest), + #[prost(message, tag="3")] + ConfirmPairing(super::BitBoxBaseConfirmPairingRequest), + #[prost(message, tag="4")] + DisplayStatus(super::BitBoxBaseDisplayStatusRequest), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcScriptConfig { + #[prost(oneof="btc_script_config::Config", tags="1, 2")] + pub config: ::core::option::Option, +} +/// Nested message and enum types in `BTCScriptConfig`. +pub mod btc_script_config { + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Multisig { + #[prost(uint32, tag="1")] + pub threshold: u32, + /// xpubs are acount-level xpubs. Addresses are going to be derived from it using: m//. + /// The number of xpubs defines the number of cosigners. + #[prost(message, repeated, tag="2")] + pub xpubs: ::prost::alloc::vec::Vec, + /// Index to the xpub of our keystore in xpubs. The keypath to it is provided via + /// BTCPubRequest/BTCSignInit. + #[prost(uint32, tag="3")] + pub our_xpub_index: u32, + } + /// SimpleType is a "simple" script: one public key, no additional inputs. + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum SimpleType { + P2wpkhP2sh = 0, + P2wpkh = 1, + } + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Config { + #[prost(enumeration="SimpleType", tag="1")] + SimpleType(i32), + #[prost(message, tag="2")] + Multisig(Multisig), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcPubRequest { + #[prost(enumeration="BtcCoin", tag="1")] + pub coin: i32, + #[prost(uint32, repeated, tag="2")] + pub keypath: ::prost::alloc::vec::Vec, + #[prost(bool, tag="5")] + pub display: bool, + #[prost(oneof="btc_pub_request::Output", tags="3, 4")] + pub output: ::core::option::Option, +} +/// Nested message and enum types in `BTCPubRequest`. +pub mod btc_pub_request { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum XPubType { + Tpub = 0, + Xpub = 1, + Ypub = 2, + /// zpub + Zpub = 3, + /// vpub + Vpub = 4, + Upub = 5, + /// Vpub + CapitalVpub = 6, + /// Zpub + CapitalZpub = 7, + } + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Output { + #[prost(enumeration="XPubType", tag="3")] + XpubType(i32), + #[prost(message, tag="4")] + ScriptConfig(super::BtcScriptConfig), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcScriptConfigWithKeypath { + #[prost(message, optional, tag="2")] + pub script_config: ::core::option::Option, + #[prost(uint32, repeated, tag="3")] + pub keypath: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcSignInitRequest { + #[prost(enumeration="BtcCoin", tag="1")] + pub coin: i32, + /// used script configs in inputs and changes + #[prost(message, repeated, tag="2")] + pub script_configs: ::prost::alloc::vec::Vec, + /// must be 1 or 2 + #[prost(uint32, tag="4")] + pub version: u32, + #[prost(uint32, tag="5")] + pub num_inputs: u32, + #[prost(uint32, tag="6")] + pub num_outputs: u32, + /// must be <500000000 + #[prost(uint32, tag="7")] + pub locktime: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcSignNextResponse { + #[prost(enumeration="btc_sign_next_response::Type", tag="1")] + pub r#type: i32, + /// index of the current input or output + #[prost(uint32, tag="2")] + pub index: u32, + /// only as a response to BTCSignInputRequest + #[prost(bool, tag="3")] + pub has_signature: bool, + /// 64 bytes (32 bytes big endian R, 32 bytes big endian S). Only if has_signature is true. + #[prost(bytes, tag="4")] + pub signature: ::prost::alloc::vec::Vec, + /// Previous tx's input/output index in case of PREV_INPUT or PREV_OUTPUT, for the input at `index`. + #[prost(uint32, tag="5")] + pub prev_index: u32, +} +/// Nested message and enum types in `BTCSignNextResponse`. +pub mod btc_sign_next_response { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum Type { + Input = 0, + Output = 1, + Done = 2, + /// For the previous transaction at input `index`. + PrevtxInit = 3, + PrevtxInput = 4, + PrevtxOutput = 5, + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcSignInputRequest { + #[prost(bytes, tag="1")] + pub prev_out_hash: ::prost::alloc::vec::Vec, + #[prost(uint32, tag="2")] + pub prev_out_index: u32, + #[prost(uint64, tag="3")] + pub prev_out_value: u64, + /// must be 0xffffffff-2, 0xffffffff-1 or 0xffffffff + #[prost(uint32, tag="4")] + pub sequence: u32, + /// all inputs must be ours. + #[prost(uint32, repeated, tag="6")] + pub keypath: ::prost::alloc::vec::Vec, + /// References a script config from BTCSignInitRequest + #[prost(uint32, tag="7")] + pub script_config_index: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcSignOutputRequest { + #[prost(bool, tag="1")] + pub ours: bool, + /// if ours is false + #[prost(enumeration="BtcOutputType", tag="2")] + pub r#type: i32, + /// 20 bytes for p2pkh, p2sh, pw2wpkh. 32 bytes for p2wsh. + #[prost(uint64, tag="3")] + pub value: u64, + /// if ours is false + #[prost(bytes, tag="4")] + pub hash: ::prost::alloc::vec::Vec, + /// if ours is true + #[prost(uint32, repeated, tag="5")] + pub keypath: ::prost::alloc::vec::Vec, + /// If ours is true. References a script config from BTCSignInitRequest + #[prost(uint32, tag="6")] + pub script_config_index: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcScriptConfigRegistration { + #[prost(enumeration="BtcCoin", tag="1")] + pub coin: i32, + #[prost(message, optional, tag="2")] + pub script_config: ::core::option::Option, + #[prost(uint32, repeated, tag="3")] + pub keypath: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcSuccess { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcIsScriptConfigRegisteredRequest { + #[prost(message, optional, tag="1")] + pub registration: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcIsScriptConfigRegisteredResponse { + #[prost(bool, tag="1")] + pub is_registered: bool, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcRegisterScriptConfigRequest { + #[prost(message, optional, tag="1")] + pub registration: ::core::option::Option, + #[prost(string, tag="2")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcPrevTxInitRequest { + #[prost(uint32, tag="1")] + pub version: u32, + #[prost(uint32, tag="2")] + pub num_inputs: u32, + #[prost(uint32, tag="3")] + pub num_outputs: u32, + #[prost(uint32, tag="4")] + pub locktime: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcPrevTxInputRequest { + #[prost(bytes, tag="1")] + pub prev_out_hash: ::prost::alloc::vec::Vec, + #[prost(uint32, tag="2")] + pub prev_out_index: u32, + #[prost(bytes, tag="3")] + pub signature_script: ::prost::alloc::vec::Vec, + #[prost(uint32, tag="4")] + pub sequence: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcPrevTxOutputRequest { + #[prost(uint64, tag="1")] + pub value: u64, + #[prost(bytes, tag="2")] + pub pubkey_script: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcRequest { + #[prost(oneof="btc_request::Request", tags="1, 2, 3, 4, 5")] + pub request: ::core::option::Option, +} +/// Nested message and enum types in `BTCRequest`. +pub mod btc_request { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Request { + #[prost(message, tag="1")] + IsScriptConfigRegistered(super::BtcIsScriptConfigRegisteredRequest), + #[prost(message, tag="2")] + RegisterScriptConfig(super::BtcRegisterScriptConfigRequest), + #[prost(message, tag="3")] + PrevtxInit(super::BtcPrevTxInitRequest), + #[prost(message, tag="4")] + PrevtxInput(super::BtcPrevTxInputRequest), + #[prost(message, tag="5")] + PrevtxOutput(super::BtcPrevTxOutputRequest), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BtcResponse { + #[prost(oneof="btc_response::Response", tags="1, 2, 3")] + pub response: ::core::option::Option, +} +/// Nested message and enum types in `BTCResponse`. +pub mod btc_response { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Response { + #[prost(message, tag="1")] + Success(super::BtcSuccess), + #[prost(message, tag="2")] + IsScriptConfigRegistered(super::BtcIsScriptConfigRegisteredResponse), + #[prost(message, tag="3")] + SignNext(super::BtcSignNextResponse), + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum BtcCoin { + Btc = 0, + Tbtc = 1, + Ltc = 2, + Tltc = 3, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum BtcOutputType { + Unknown = 0, + P2pkh = 1, + P2sh = 2, + P2wpkh = 3, + P2wsh = 4, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EthPubRequest { + #[prost(uint32, repeated, tag="1")] + pub keypath: ::prost::alloc::vec::Vec, + #[prost(enumeration="EthCoin", tag="2")] + pub coin: i32, + #[prost(enumeration="eth_pub_request::OutputType", tag="3")] + pub output_type: i32, + #[prost(bool, tag="4")] + pub display: bool, + #[prost(bytes, tag="5")] + pub contract_address: ::prost::alloc::vec::Vec, +} +/// Nested message and enum types in `ETHPubRequest`. +pub mod eth_pub_request { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] + #[repr(i32)] + pub enum OutputType { + Address = 0, + Xpub = 1, + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EthSignRequest { + #[prost(enumeration="EthCoin", tag="1")] + pub coin: i32, + #[prost(uint32, repeated, tag="2")] + pub keypath: ::prost::alloc::vec::Vec, + /// smallest big endian serialization, max. 16 bytes + #[prost(bytes, tag="3")] + pub nonce: ::prost::alloc::vec::Vec, + /// smallest big endian serialization, max. 16 bytes + #[prost(bytes, tag="4")] + pub gas_price: ::prost::alloc::vec::Vec, + /// smallest big endian serialization, max. 16 bytes + #[prost(bytes, tag="5")] + pub gas_limit: ::prost::alloc::vec::Vec, + /// 20 byte recipient + #[prost(bytes, tag="6")] + pub recipient: ::prost::alloc::vec::Vec, + /// smallest big endian serialization, max. 32 bytes + #[prost(bytes, tag="7")] + pub value: ::prost::alloc::vec::Vec, + #[prost(bytes, tag="8")] + pub data: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EthSignMessageRequest { + #[prost(enumeration="EthCoin", tag="1")] + pub coin: i32, + #[prost(uint32, repeated, tag="2")] + pub keypath: ::prost::alloc::vec::Vec, + #[prost(bytes, tag="3")] + pub msg: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EthSignResponse { + /// 65 bytes, last byte is the recid + #[prost(bytes, tag="1")] + pub signature: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EthRequest { + #[prost(oneof="eth_request::Request", tags="1, 2, 3")] + pub request: ::core::option::Option, +} +/// Nested message and enum types in `ETHRequest`. +pub mod eth_request { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Request { + #[prost(message, tag="1")] + Pub(super::EthPubRequest), + #[prost(message, tag="2")] + Sign(super::EthSignRequest), + #[prost(message, tag="3")] + SignMsg(super::EthSignMessageRequest), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EthResponse { + #[prost(oneof="eth_response::Response", tags="1, 2")] + pub response: ::core::option::Option, +} +/// Nested message and enum types in `ETHResponse`. +pub mod eth_response { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Response { + #[prost(message, tag="1")] + Pub(super::PubResponse), + #[prost(message, tag="2")] + Sign(super::EthSignResponse), + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum EthCoin { + Eth = 0, + RopstenEth = 1, + RinkebyEth = 2, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ElectrumEncryptionKeyRequest { + #[prost(uint32, repeated, tag="1")] + pub keypath: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ElectrumEncryptionKeyResponse { + #[prost(string, tag="1")] + pub key: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ShowMnemonicRequest { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RestoreFromMnemonicRequest { + #[prost(uint32, tag="1")] + pub timestamp: u32, + #[prost(int32, tag="2")] + pub timezone_offset: i32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SetMnemonicPassphraseEnabledRequest { + #[prost(bool, tag="1")] + pub enabled: bool, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RandomNumberResponse { + #[prost(bytes, tag="1")] + pub number: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RandomNumberRequest { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RebootRequest { +} +/// Deprecated, last used in v1.0.0 +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerformAttestationRequest { + /// 32 bytes challenge. + #[prost(bytes, tag="1")] + pub challenge: ::prost::alloc::vec::Vec, +} +/// Deprecated, last used in v1.0.0 +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerformAttestationResponse { + #[prost(bytes, tag="1")] + pub bootloader_hash: ::prost::alloc::vec::Vec, + #[prost(bytes, tag="2")] + pub device_pubkey: ::prost::alloc::vec::Vec, + #[prost(bytes, tag="3")] + pub certificate: ::prost::alloc::vec::Vec, + #[prost(bytes, tag="4")] + pub root_pubkey_identifier: ::prost::alloc::vec::Vec, + #[prost(bytes, tag="5")] + pub challenge_signature: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Error { + #[prost(int32, tag="1")] + pub code: i32, + #[prost(string, tag="2")] + pub message: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Success { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Request { + #[prost(oneof="request::Request", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26")] + pub request: ::core::option::Option, +} +/// Nested message and enum types in `Request`. +pub mod request { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Request { + #[prost(message, tag="1")] + RandomNumber(super::RandomNumberRequest), + #[prost(message, tag="2")] + DeviceName(super::SetDeviceNameRequest), + #[prost(message, tag="3")] + DeviceLanguage(super::SetDeviceLanguageRequest), + #[prost(message, tag="4")] + DeviceInfo(super::DeviceInfoRequest), + #[prost(message, tag="5")] + SetPassword(super::SetPasswordRequest), + #[prost(message, tag="6")] + CreateBackup(super::CreateBackupRequest), + #[prost(message, tag="7")] + ShowMnemonic(super::ShowMnemonicRequest), + #[prost(message, tag="8")] + BtcPub(super::BtcPubRequest), + #[prost(message, tag="9")] + BtcSignInit(super::BtcSignInitRequest), + #[prost(message, tag="10")] + BtcSignInput(super::BtcSignInputRequest), + #[prost(message, tag="11")] + BtcSignOutput(super::BtcSignOutputRequest), + #[prost(message, tag="12")] + InsertRemoveSdcard(super::InsertRemoveSdCardRequest), + #[prost(message, tag="13")] + CheckSdcard(super::CheckSdCardRequest), + #[prost(message, tag="14")] + SetMnemonicPassphraseEnabled(super::SetMnemonicPassphraseEnabledRequest), + #[prost(message, tag="15")] + ListBackups(super::ListBackupsRequest), + #[prost(message, tag="16")] + RestoreBackup(super::RestoreBackupRequest), + #[prost(message, tag="17")] + PerformAttestation(super::PerformAttestationRequest), + #[prost(message, tag="18")] + Reboot(super::RebootRequest), + #[prost(message, tag="19")] + CheckBackup(super::CheckBackupRequest), + #[prost(message, tag="20")] + Eth(super::EthRequest), + #[prost(message, tag="21")] + Reset(super::ResetRequest), + #[prost(message, tag="22")] + RestoreFromMnemonic(super::RestoreFromMnemonicRequest), + #[prost(message, tag="23")] + Bitboxbase(super::BitBoxBaseRequest), + #[prost(message, tag="24")] + Fingerprint(super::RootFingerprintRequest), + #[prost(message, tag="25")] + Btc(super::BtcRequest), + #[prost(message, tag="26")] + ElectrumEncryptionKey(super::ElectrumEncryptionKeyRequest), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Response { + #[prost(oneof="response::Response", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14")] + pub response: ::core::option::Option, +} +/// Nested message and enum types in `Response`. +pub mod response { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Response { + #[prost(message, tag="1")] + Success(super::Success), + #[prost(message, tag="2")] + Error(super::Error), + #[prost(message, tag="3")] + RandomNumber(super::RandomNumberResponse), + #[prost(message, tag="4")] + DeviceInfo(super::DeviceInfoResponse), + #[prost(message, tag="5")] + Pub(super::PubResponse), + #[prost(message, tag="6")] + BtcSignNext(super::BtcSignNextResponse), + #[prost(message, tag="7")] + ListBackups(super::ListBackupsResponse), + #[prost(message, tag="8")] + CheckBackup(super::CheckBackupResponse), + #[prost(message, tag="9")] + PerformAttestation(super::PerformAttestationResponse), + #[prost(message, tag="10")] + CheckSdcard(super::CheckSdCardResponse), + #[prost(message, tag="11")] + Eth(super::EthResponse), + #[prost(message, tag="12")] + Fingerprint(super::RootFingerprintResponse), + #[prost(message, tag="13")] + Btc(super::BtcResponse), + #[prost(message, tag="14")] + ElectrumEncryptionKey(super::ElectrumEncryptionKeyResponse), + } +} diff --git a/src/rust/bitbox02-rust/src/hww/mod.rs b/src/rust/bitbox02-rust/src/hww/mod.rs index c6cf9fbbf..d3a57627d 100644 --- a/src/rust/bitbox02-rust/src/hww/mod.rs +++ b/src/rust/bitbox02-rust/src/hww/mod.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod api; pub mod noise; extern crate alloc; diff --git a/src/rust/bitbox02-rust/src/hww/noise.rs b/src/rust/bitbox02-rust/src/hww/noise.rs index 0d45252c4..dfd3d97d3 100644 --- a/src/rust/bitbox02-rust/src/hww/noise.rs +++ b/src/rust/bitbox02-rust/src/hww/noise.rs @@ -117,7 +117,7 @@ pub(crate) async fn process(usb_in: Vec, usb_out: &mut Vec) -> Result<() } Some((&OP_NOISE_MSG, encrypted_msg)) => { let decrypted_msg = state.decrypt(encrypted_msg)?; - let response = bitbox02::commander::commander(decrypted_msg); + let response = super::api::process(decrypted_msg).await; state.encrypt(&response, usb_out)?; Ok(()) } diff --git a/src/rust/bitbox02-rust/src/workflow/unlock.rs b/src/rust/bitbox02-rust/src/workflow/unlock.rs index dfa5eea45..4685475a1 100644 --- a/src/rust/bitbox02-rust/src/workflow/unlock.rs +++ b/src/rust/bitbox02-rust/src/workflow/unlock.rs @@ -66,7 +66,7 @@ pub async fn unlock_keystore(title: &str) -> bool { Ok(()) => true, Err(keystore::Error::IncorrectPassword { remaining_attempts }) => { let msg = match remaining_attempts { - 1 => format!("Wrong password\n1 try remains"), + 1 => "Wrong password\n1 try remains".into(), n => format!("Wrong password\n{} tries remain", n), }; status(&msg, false).await; diff --git a/src/rust/bitbox02-sys/wrapper.h b/src/rust/bitbox02-sys/wrapper.h index 05ce9ed53..b199f9609 100644 --- a/src/rust/bitbox02-sys/wrapper.h +++ b/src/rust/bitbox02-sys/wrapper.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/src/rust/bitbox02/src/commander.rs b/src/rust/bitbox02/src/commander.rs index 643b82cab..19ad92177 100644 --- a/src/rust/bitbox02/src/commander.rs +++ b/src/rust/bitbox02/src/commander.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub type Error = bitbox02_sys::commander_error_t; +pub use bitbox02_sys::commander_error_t as Error; extern crate alloc; use alloc::vec::Vec; @@ -44,3 +44,11 @@ pub fn commander(input: Vec) -> Vec { }; output_vec } + +pub fn states_can_call(request_tag: u16) -> bool { + unsafe { bitbox02_sys::commander_states_can_call(request_tag) } +} + +pub fn states_clear_force_next() { + unsafe { bitbox02_sys::commander_states_clear_force_next() } +} diff --git a/src/rust/bitbox02/src/lib.rs b/src/rust/bitbox02/src/lib.rs index d82f68862..339f803de 100644 --- a/src/rust/bitbox02/src/lib.rs +++ b/src/rust/bitbox02/src/lib.rs @@ -55,6 +55,18 @@ pub const BitBoxBaseRequest_display_status_tag: u16 = pub const BitBoxBaseRequest_set_config_tag: u16 = bitbox02_sys::BitBoxBaseRequest_set_config_tag as u16; +pub use bitbox02_sys::{ + Request_bitboxbase_tag, Request_btc_pub_tag, Request_btc_sign_init_tag, + Request_btc_sign_input_tag, Request_btc_sign_output_tag, Request_btc_tag, + Request_check_backup_tag, Request_check_sdcard_tag, Request_create_backup_tag, + Request_device_info_tag, Request_device_language_tag, Request_device_name_tag, + Request_electrum_encryption_key_tag, Request_eth_tag, Request_fingerprint_tag, + Request_insert_remove_sdcard_tag, Request_list_backups_tag, Request_perform_attestation_tag, + Request_random_number_tag, Request_reboot_tag, Request_reset_tag, Request_restore_backup_tag, + Request_restore_from_mnemonic_tag, Request_set_mnemonic_passphrase_enabled_tag, + Request_set_password_tag, Request_show_mnemonic_tag, +}; + // Use this for functions exported to "C" #[allow(non_camel_case_types)] pub type commander_error_t = bitbox02_sys::commander_error_t; diff --git a/src/rust/vendor/anyhow/.cargo-checksum.json b/src/rust/vendor/anyhow/.cargo-checksum.json new file mode 100644 index 000000000..6d27f51df --- /dev/null +++ b/src/rust/vendor/anyhow/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"21a48fbff0c6c0c47cf7af970348c3701cc8220e04a191d3a00def58250317f1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"0d9c5facc3db17123752af8c3dbcdb9bb3785c8ed046b27de26669e4e87f131c","build.rs":"d8b58acc2cd88d627763135b3b25b46f276e2672ef740efb7fb5b1404fb230d8","src/backtrace.rs":"a82a8ffae2c68ee385dc78d8ec8cb6f3351234f0ad6af7e87df2371593e0f6aa","src/chain.rs":"1627608ce95c3484d26e1742a1b8b533b74c6159916b717bacffae3ae53731f9","src/context.rs":"f2be36af9588c924ed087bcb7bd681d330889e54b8f98cdc2aba93512a28762e","src/error.rs":"2c6a51880c7379265f7f7b6557e7bed808ff0f3267337a0c77dbbc1d2c4662e7","src/fmt.rs":"dd0593a2e20487165ec5889e72cc8833eee4fa69ac258420428eede8e17f2213","src/kind.rs":"8481a8b7835eebb3859a8c32c217bf9c73543cfc62e3916b98d39af8b063125c","src/lib.rs":"9ca1763c7964b9a547456121b2e5af099a0622e369e8c991e9cd46ad793c08ce","src/macros.rs":"77722190b58a6106b21aefd3b5d4f136a076afcdbc0fae21562d99e2c22912e1","src/wrapper.rs":"1229beca67dbd95ca77c9ecce282272acc55276c267c58cb73a75388b4693dda","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"0a52a44786aea1c299c695bf948b2ed2081e4cc344e5c2cadceab4eb03d0010d","tests/drop/mod.rs":"464bc1ddeae307eac906928286ec3edb77057c5c1302e02150d3649e2b861f1a","tests/test_autotrait.rs":"981e792db353be2f14c7a1cabe43b5f1329c168cb7679077cc2be786a0920d48","tests/test_backtrace.rs":"0e50edbb33b6bd07ba89ff3db72fb7c688ba2a4371fccdbbb20309ab02948b6a","tests/test_boxed.rs":"98a45325b1e86d4c5d3094ab99cd1ada1f771c505d2d7322f0afcbe7bdb71cfa","tests/test_chain.rs":"f28efeae7395d1c395e6f1a647b4199c25a00410ade45248c145c6fcf2fb448a","tests/test_context.rs":"f82c915b182df1a604a4cd558a03b1a821414983d6f6af6822398104cea70676","tests/test_convert.rs":"62840be1ee8022ba5e8c0d3fc1752a1526b2c47d4cceecff2b86790524c3b3ea","tests/test_downcast.rs":"253d6f54e554965023b378b037827ec6289c4779a7a7c12706e19c2731d219fe","tests/test_fmt.rs":"17572596f257aac9aa2ec4620e292ca6a954128b94772bb948399fab53832e70","tests/test_macros.rs":"c7d3d5e0b756f59d4858035025fb341d031369c88486fd9f961ee16bae6c78bf","tests/test_repr.rs":"dbb9b04ddbe1ab31eb5331ea69f05bb3a147299da2275a3d4dcc92947b5591b9","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"7c2c3f46c266a437300591f10be330f937ac6a0a2213ed5030a9fbc895e2d100"},"package":"85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"} \ No newline at end of file diff --git a/src/rust/vendor/anyhow/Cargo.toml b/src/rust/vendor/anyhow/Cargo.toml new file mode 100644 index 000000000..0b1441660 --- /dev/null +++ b/src/rust/vendor/anyhow/Cargo.toml @@ -0,0 +1,43 @@ +# 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 = "anyhow" +version = "1.0.31" +authors = ["David Tolnay "] +description = "Flexible concrete Error type built on std::error::Error" +documentation = "https://docs.rs/anyhow" +readme = "README.md" +categories = ["rust-patterns"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/anyhow" +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "doc_cfg"] +targets = ["x86_64-unknown-linux-gnu"] +[dev-dependencies.futures] +version = "0.3" +default-features = false + +[dev-dependencies.rustversion] +version = "1.0" + +[dev-dependencies.thiserror] +version = "1.0" + +[dev-dependencies.trybuild] +version = "1.0.19" +features = ["diff"] + +[features] +default = ["std"] +std = [] diff --git a/src/rust/vendor/anyhow/LICENSE-APACHE b/src/rust/vendor/anyhow/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/anyhow/LICENSE-APACHE @@ -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. diff --git a/src/rust/vendor/anyhow/LICENSE-MIT b/src/rust/vendor/anyhow/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/src/rust/vendor/anyhow/LICENSE-MIT @@ -0,0 +1,23 @@ +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. diff --git a/src/rust/vendor/anyhow/README.md b/src/rust/vendor/anyhow/README.md new file mode 100644 index 000000000..87b41d795 --- /dev/null +++ b/src/rust/vendor/anyhow/README.md @@ -0,0 +1,176 @@ +Anyhow ¯\\\_(ツ)\_/¯ +========================= + +[github](https://github.com/dtolnay/anyhow) +[crates.io](https://crates.io/crates/anyhow) +[docs.rs](https://docs.rs/anyhow) +[build status](https://github.com/dtolnay/anyhow/actions?query=branch%3Amaster) + +This library provides [`anyhow::Error`][Error], a trait object based error type +for easy idiomatic error handling in Rust applications. + +[Error]: https://docs.rs/anyhow/1.0/anyhow/struct.Error.html + +```toml +[dependencies] +anyhow = "1.0" +``` + +*Compiler support: requires rustc 1.34+* + +
+ +## Details + +- Use `Result`, or equivalently `anyhow::Result`, as the + return type of any fallible function. + + Within the function, use `?` to easily propagate any error that implements the + `std::error::Error` trait. + + ```rust + use anyhow::Result; + + fn get_cluster_info() -> Result { + let config = std::fs::read_to_string("cluster.json")?; + let map: ClusterMap = serde_json::from_str(&config)?; + Ok(map) + } + ``` + +- Attach context to help the person troubleshooting the error understand where + things went wrong. A low-level error like "No such file or directory" can be + annoying to debug without more context about what higher level step the + application was in the middle of. + + ```rust + use anyhow::{Context, Result}; + + fn main() -> Result<()> { + ... + it.detach().context("Failed to detach the important thing")?; + + let content = std::fs::read(path) + .with_context(|| format!("Failed to read instrs from {}", path))?; + ... + } + ``` + + ```console + Error: Failed to read instrs from ./path/to/instrs.json + + Caused by: + No such file or directory (os error 2) + ``` + +- Downcasting is supported and can be by value, by shared reference, or by + mutable reference as needed. + + ```rust + // If the error was caused by redaction, then return a + // tombstone instead of the content. + match root_cause.downcast_ref::() { + Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), + None => Err(error), + } + ``` + +- If using the nightly channel, a backtrace is captured and printed with the + error if the underlying error type does not already provide its own. In order + to see backtraces, they must be enabled through the environment variables + described in [`std::backtrace`]: + + - If you want panics and errors to both have backtraces, set + `RUST_BACKTRACE=1`; + - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; + - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and + `RUST_LIB_BACKTRACE=0`. + + The tracking issue for this feature is [rust-lang/rust#53487]. + + [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables + [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487 + +- Anyhow works with any error type that has an impl of `std::error::Error`, + including ones defined in your crate. We do not bundle a `derive(Error)` macro + but you can write the impls yourself or use a standalone macro like + [thiserror]. + + ```rust + use thiserror::Error; + + #[derive(Error, Debug)] + pub enum FormatError { + #[error("Invalid header (expected {expected:?}, got {found:?})")] + InvalidHeader { + expected: String, + found: String, + }, + #[error("Missing attribute: {0}")] + MissingAttribute(String), + } + ``` + +- One-off error messages can be constructed using the `anyhow!` macro, which + supports string interpolation and produces an `anyhow::Error`. + + ```rust + return Err(anyhow!("Missing attribute: {}", missing)); + ``` + +
+ +## No-std support + +In no_std mode, the same API is almost all available and works the same way. To +depend on Anyhow in no_std mode, disable our default enabled "std" feature in +Cargo.toml. A global allocator is required. + +```toml +[dependencies] +anyhow = { version = "1.0", default-features = false } +``` + +Since the `?`-based error conversions would normally rely on the +`std::error::Error` trait which is only available through std, no_std mode will +require an explicit `.map_err(Error::msg)` when working with a non-Anyhow error +type inside a function that returns Anyhow's error type. + +
+ +## Comparison to failure + +The `anyhow::Error` type works something like `failure::Error`, but unlike +failure ours is built around the standard library's `std::error::Error` trait +rather than a separate trait `failure::Fail`. The standard library has adopted +the necessary improvements for this to be possible as part of [RFC 2504]. + +[RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md + +
+ +## Comparison to thiserror + +Use Anyhow if you don't care what error type your functions return, you just +want it to be easy. This is common in application code. Use [thiserror] if you +are a library that wants to design your own dedicated error type(s) so that on +failures the caller gets exactly the information that you choose. + +[thiserror]: https://github.com/dtolnay/thiserror + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/src/rust/vendor/anyhow/build.rs b/src/rust/vendor/anyhow/build.rs new file mode 100644 index 000000000..d20b0721d --- /dev/null +++ b/src/rust/vendor/anyhow/build.rs @@ -0,0 +1,63 @@ +use std::env; +use std::fs; +use std::path::Path; +use std::process::{Command, ExitStatus, Stdio}; + +// This code exercises the surface area that we expect of the std Backtrace +// type. If the current toolchain is able to compile it, we go ahead and use +// backtrace in anyhow. +const PROBE: &str = r#" + #![feature(backtrace)] + #![allow(dead_code)] + + use std::backtrace::{Backtrace, BacktraceStatus}; + use std::error::Error; + use std::fmt::{self, Display}; + + #[derive(Debug)] + struct E; + + impl Display for E { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + unimplemented!() + } + } + + impl Error for E { + fn backtrace(&self) -> Option<&Backtrace> { + let backtrace = Backtrace::capture(); + match backtrace.status() { + BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {} + } + unimplemented!() + } + } +"#; + +fn main() { + if !cfg!(feature = "std") { + return; + } + match compile_probe() { + Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"), + _ => {} + } +} + +fn compile_probe() -> Option { + let rustc = env::var_os("RUSTC")?; + let out_dir = env::var_os("OUT_DIR")?; + let probefile = Path::new(&out_dir).join("probe.rs"); + fs::write(&probefile, PROBE).ok()?; + Command::new(rustc) + .stderr(Stdio::null()) + .arg("--edition=2018") + .arg("--crate-name=anyhow_build") + .arg("--crate-type=lib") + .arg("--emit=metadata") + .arg("--out-dir") + .arg(out_dir) + .arg(probefile) + .status() + .ok() +} diff --git a/src/rust/vendor/anyhow/src/backtrace.rs b/src/rust/vendor/anyhow/src/backtrace.rs new file mode 100644 index 000000000..01e33cb23 --- /dev/null +++ b/src/rust/vendor/anyhow/src/backtrace.rs @@ -0,0 +1,36 @@ +#[cfg(backtrace)] +pub(crate) use std::backtrace::Backtrace; + +#[cfg(not(backtrace))] +pub(crate) enum Backtrace {} + +#[cfg(backtrace)] +macro_rules! backtrace { + () => { + Some(Backtrace::capture()) + }; +} + +#[cfg(not(backtrace))] +macro_rules! backtrace { + () => { + None + }; +} + +#[cfg(backtrace)] +macro_rules! backtrace_if_absent { + ($err:expr) => { + match $err.backtrace() { + Some(_) => None, + None => Some(Backtrace::capture()), + } + }; +} + +#[cfg(all(feature = "std", not(backtrace)))] +macro_rules! backtrace_if_absent { + ($err:expr) => { + None + }; +} diff --git a/src/rust/vendor/anyhow/src/chain.rs b/src/rust/vendor/anyhow/src/chain.rs new file mode 100644 index 000000000..207e4f0ca --- /dev/null +++ b/src/rust/vendor/anyhow/src/chain.rs @@ -0,0 +1,101 @@ +use self::ChainState::*; +use crate::StdError; + +#[cfg(feature = "std")] +use std::vec; + +#[cfg(feature = "std")] +pub(crate) use crate::Chain; + +#[cfg(not(feature = "std"))] +pub(crate) struct Chain<'a> { + state: ChainState<'a>, +} + +#[derive(Clone)] +pub(crate) enum ChainState<'a> { + Linked { + next: Option<&'a (dyn StdError + 'static)>, + }, + #[cfg(feature = "std")] + Buffered { + rest: vec::IntoIter<&'a (dyn StdError + 'static)>, + }, +} + +impl<'a> Chain<'a> { + pub fn new(head: &'a (dyn StdError + 'static)) -> Self { + Chain { + state: ChainState::Linked { next: Some(head) }, + } + } +} + +impl<'a> Iterator for Chain<'a> { + type Item = &'a (dyn StdError + 'static); + + fn next(&mut self) -> Option { + match &mut self.state { + Linked { next } => { + let error = (*next)?; + *next = error.source(); + Some(error) + } + #[cfg(feature = "std")] + Buffered { rest } => rest.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +#[cfg(feature = "std")] +impl DoubleEndedIterator for Chain<'_> { + fn next_back(&mut self) -> Option { + match &mut self.state { + Linked { mut next } => { + let mut rest = Vec::new(); + while let Some(cause) = next { + next = cause.source(); + rest.push(cause); + } + let mut rest = rest.into_iter(); + let last = rest.next_back(); + self.state = Buffered { rest }; + last + } + Buffered { rest } => rest.next_back(), + } + } +} + +impl ExactSizeIterator for Chain<'_> { + fn len(&self) -> usize { + match &self.state { + Linked { mut next } => { + let mut len = 0; + while let Some(cause) = next { + next = cause.source(); + len += 1; + } + len + } + #[cfg(feature = "std")] + Buffered { rest } => rest.len(), + } + } +} + +#[cfg(feature = "std")] +impl Default for Chain<'_> { + fn default() -> Self { + Chain { + state: ChainState::Buffered { + rest: Vec::new().into_iter(), + }, + } + } +} diff --git a/src/rust/vendor/anyhow/src/context.rs b/src/rust/vendor/anyhow/src/context.rs new file mode 100644 index 000000000..25d34114c --- /dev/null +++ b/src/rust/vendor/anyhow/src/context.rs @@ -0,0 +1,177 @@ +use crate::error::ContextError; +use crate::{Context, Error, StdError}; +use core::convert::Infallible; +use core::fmt::{self, Debug, Display, Write}; + +#[cfg(backtrace)] +use std::backtrace::Backtrace; + +mod ext { + use super::*; + + pub trait StdError { + fn ext_context(self, context: C) -> Error + where + C: Display + Send + Sync + 'static; + } + + #[cfg(feature = "std")] + impl StdError for E + where + E: std::error::Error + Send + Sync + 'static, + { + fn ext_context(self, context: C) -> Error + where + C: Display + Send + Sync + 'static, + { + let backtrace = backtrace_if_absent!(self); + Error::from_context(context, self, backtrace) + } + } + + impl StdError for Error { + fn ext_context(self, context: C) -> Error + where + C: Display + Send + Sync + 'static, + { + self.context(context) + } + } +} + +impl Context for Result +where + E: ext::StdError + Send + Sync + 'static, +{ + fn context(self, context: C) -> Result + where + C: Display + Send + Sync + 'static, + { + self.map_err(|error| error.ext_context(context)) + } + + fn with_context(self, context: F) -> Result + where + C: Display + Send + Sync + 'static, + F: FnOnce() -> C, + { + self.map_err(|error| error.ext_context(context())) + } +} + +/// ``` +/// # type T = (); +/// # +/// use anyhow::{Context, Result}; +/// +/// fn maybe_get() -> Option { +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # unimplemented!() +/// } +/// +/// fn demo() -> Result<()> { +/// let t = maybe_get().context("there is no T")?; +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # unimplemented!() +/// } +/// ``` +impl Context for Option { + fn context(self, context: C) -> Result + where + C: Display + Send + Sync + 'static, + { + self.ok_or_else(|| Error::from_display(context, backtrace!())) + } + + fn with_context(self, context: F) -> Result + where + C: Display + Send + Sync + 'static, + F: FnOnce() -> C, + { + self.ok_or_else(|| Error::from_display(context(), backtrace!())) + } +} + +impl Debug for ContextError +where + C: Display, + E: Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Error") + .field("context", &Quoted(&self.context)) + .field("source", &self.error) + .finish() + } +} + +impl Display for ContextError +where + C: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.context, f) + } +} + +impl StdError for ContextError +where + C: Display, + E: StdError + 'static, +{ + #[cfg(backtrace)] + fn backtrace(&self) -> Option<&Backtrace> { + self.error.backtrace() + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(&self.error) + } +} + +impl StdError for ContextError +where + C: Display, +{ + #[cfg(backtrace)] + fn backtrace(&self) -> Option<&Backtrace> { + Some(self.error.backtrace()) + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(self.error.inner.error()) + } +} + +struct Quoted(C); + +impl Debug for Quoted +where + C: Display, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_char('"')?; + Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?; + formatter.write_char('"')?; + Ok(()) + } +} + +impl Write for Quoted<&mut fmt::Formatter<'_>> { + fn write_str(&mut self, s: &str) -> fmt::Result { + Display::fmt(&s.escape_debug(), self.0) + } +} + +pub(crate) mod private { + use super::*; + + pub trait Sealed {} + + impl Sealed for Result where E: ext::StdError {} + impl Sealed for Option {} +} diff --git a/src/rust/vendor/anyhow/src/error.rs b/src/rust/vendor/anyhow/src/error.rs new file mode 100644 index 000000000..80d879f84 --- /dev/null +++ b/src/rust/vendor/anyhow/src/error.rs @@ -0,0 +1,802 @@ +use crate::alloc::Box; +use crate::backtrace::Backtrace; +use crate::chain::Chain; +use crate::{Error, StdError}; +use core::any::TypeId; +use core::fmt::{self, Debug, Display}; +use core::mem::{self, ManuallyDrop}; +use core::ptr::{self, NonNull}; + +#[cfg(feature = "std")] +use core::ops::{Deref, DerefMut}; + +impl Error { + /// Create a new error object from any error type. + /// + /// The error type must be threadsafe and `'static`, so that the `Error` + /// will be as well. + /// + /// If the error type does not provide a backtrace, a backtrace will be + /// created here to ensure that a backtrace exists. + #[cfg(feature = "std")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] + pub fn new(error: E) -> Self + where + E: StdError + Send + Sync + 'static, + { + let backtrace = backtrace_if_absent!(error); + Error::from_std(error, backtrace) + } + + /// Create a new error object from a printable error message. + /// + /// If the argument implements std::error::Error, prefer `Error::new` + /// instead which preserves the underlying error's cause chain and + /// backtrace. If the argument may or may not implement std::error::Error + /// now or in the future, use `anyhow!(err)` which handles either way + /// correctly. + /// + /// `Error::msg("...")` is equivalent to `anyhow!("...")` but occasionally + /// convenient in places where a function is preferable over a macro, such + /// as iterator or stream combinators: + /// + /// ``` + /// # mod ffi { + /// # pub struct Input; + /// # pub struct Output; + /// # pub async fn do_some_work(_: Input) -> Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # use ffi::{Input, Output}; + /// # + /// use anyhow::{Error, Result}; + /// use futures::stream::{Stream, StreamExt, TryStreamExt}; + /// + /// async fn demo(stream: S) -> Result> + /// where + /// S: Stream, + /// { + /// stream + /// .then(ffi::do_some_work) // returns Result + /// .map_err(Error::msg) + /// .try_collect() + /// .await + /// } + /// ``` + pub fn msg(message: M) -> Self + where + M: Display + Debug + Send + Sync + 'static, + { + Error::from_adhoc(message, backtrace!()) + } + + #[cfg(feature = "std")] + pub(crate) fn from_std(error: E, backtrace: Option) -> Self + where + E: StdError + Send + Sync + 'static, + { + let vtable = &ErrorVTable { + object_drop: object_drop::, + object_ref: object_ref::, + #[cfg(feature = "std")] + object_mut: object_mut::, + object_boxed: object_boxed::, + object_downcast: object_downcast::, + object_drop_rest: object_drop_front::, + }; + + // Safety: passing vtable that operates on the right type E. + unsafe { Error::construct(error, vtable, backtrace) } + } + + pub(crate) fn from_adhoc(message: M, backtrace: Option) -> Self + where + M: Display + Debug + Send + Sync + 'static, + { + use crate::wrapper::MessageError; + let error: MessageError = MessageError(message); + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + #[cfg(feature = "std")] + object_mut: object_mut::>, + object_boxed: object_boxed::>, + object_downcast: object_downcast::, + object_drop_rest: object_drop_front::, + }; + + // Safety: MessageError is repr(transparent) so it is okay for the + // vtable to allow casting the MessageError to M. + unsafe { Error::construct(error, vtable, backtrace) } + } + + pub(crate) fn from_display(message: M, backtrace: Option) -> Self + where + M: Display + Send + Sync + 'static, + { + use crate::wrapper::DisplayError; + let error: DisplayError = DisplayError(message); + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + #[cfg(feature = "std")] + object_mut: object_mut::>, + object_boxed: object_boxed::>, + object_downcast: object_downcast::, + object_drop_rest: object_drop_front::, + }; + + // Safety: DisplayError is repr(transparent) so it is okay for the + // vtable to allow casting the DisplayError to M. + unsafe { Error::construct(error, vtable, backtrace) } + } + + #[cfg(feature = "std")] + pub(crate) fn from_context(context: C, error: E, backtrace: Option) -> Self + where + C: Display + Send + Sync + 'static, + E: StdError + Send + Sync + 'static, + { + let error: ContextError = ContextError { context, error }; + + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + #[cfg(feature = "std")] + object_mut: object_mut::>, + object_boxed: object_boxed::>, + object_downcast: context_downcast::, + object_drop_rest: context_drop_rest::, + }; + + // Safety: passing vtable that operates on the right type. + unsafe { Error::construct(error, vtable, backtrace) } + } + + #[cfg(feature = "std")] + pub(crate) fn from_boxed( + error: Box, + backtrace: Option, + ) -> Self { + use crate::wrapper::BoxedError; + let error = BoxedError(error); + let vtable = &ErrorVTable { + object_drop: object_drop::, + object_ref: object_ref::, + #[cfg(feature = "std")] + object_mut: object_mut::, + object_boxed: object_boxed::, + object_downcast: object_downcast::>, + object_drop_rest: object_drop_front::>, + }; + + // Safety: BoxedError is repr(transparent) so it is okay for the vtable + // to allow casting to Box. + unsafe { Error::construct(error, vtable, backtrace) } + } + + // Takes backtrace as argument rather than capturing it here so that the + // user sees one fewer layer of wrapping noise in the backtrace. + // + // Unsafe because the given vtable must have sensible behavior on the error + // value of type E. + unsafe fn construct( + error: E, + vtable: &'static ErrorVTable, + backtrace: Option, + ) -> Self + where + E: StdError + Send + Sync + 'static, + { + let inner = Box::new(ErrorImpl { + vtable, + backtrace, + _object: error, + }); + // Erase the concrete type of E from the compile-time type system. This + // is equivalent to the safe unsize coersion from Box> to + // Box> except that the + // result is a thin pointer. The necessary behavior for manipulating the + // underlying ErrorImpl is preserved in the vtable provided by the + // caller rather than a builtin fat pointer vtable. + let erased = mem::transmute::>, Box>>(inner); + let inner = ManuallyDrop::new(erased); + Error { inner } + } + + /// Wrap the error value with additional context. + /// + /// For attaching context to a `Result` as it is propagated, the + /// [`Context`][crate::Context] extension trait may be more convenient than + /// this function. + /// + /// The primary reason to use `error.context(...)` instead of + /// `result.context(...)` via the `Context` trait would be if the context + /// needs to depend on some data held by the underlying error: + /// + /// ``` + /// # use std::fmt::{self, Debug, Display}; + /// # + /// # type T = (); + /// # + /// # impl std::error::Error for ParseError {} + /// # impl Debug for ParseError { + /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// # unimplemented!() + /// # } + /// # } + /// # impl Display for ParseError { + /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use anyhow::Result; + /// use std::fs::File; + /// use std::path::Path; + /// + /// struct ParseError { + /// line: usize, + /// column: usize, + /// } + /// + /// fn parse_impl(file: File) -> Result { + /// # const IGNORE: &str = stringify! { + /// ... + /// # }; + /// # unimplemented!() + /// } + /// + /// pub fn parse(path: impl AsRef) -> Result { + /// let file = File::open(&path)?; + /// parse_impl(file).map_err(|error| { + /// let context = format!( + /// "only the first {} lines of {} are valid", + /// error.line, path.as_ref().display(), + /// ); + /// anyhow::Error::new(error).context(context) + /// }) + /// } + /// ``` + pub fn context(self, context: C) -> Self + where + C: Display + Send + Sync + 'static, + { + let error: ContextError = ContextError { + context, + error: self, + }; + + let vtable = &ErrorVTable { + object_drop: object_drop::>, + object_ref: object_ref::>, + #[cfg(feature = "std")] + object_mut: object_mut::>, + object_boxed: object_boxed::>, + object_downcast: context_chain_downcast::, + object_drop_rest: context_chain_drop_rest::, + }; + + // As the cause is anyhow::Error, we already have a backtrace for it. + let backtrace = None; + + // Safety: passing vtable that operates on the right type. + unsafe { Error::construct(error, vtable, backtrace) } + } + + /// Get the backtrace for this Error. + /// + /// Backtraces are only available on the nightly channel. Tracking issue: + /// [rust-lang/rust#53487][tracking]. + /// + /// In order for the backtrace to be meaningful, one of the two environment + /// variables `RUST_LIB_BACKTRACE=1` or `RUST_BACKTRACE=1` must be defined + /// and `RUST_LIB_BACKTRACE` must not be `0`. Backtraces are somewhat + /// expensive to capture in Rust, so we don't necessarily want to be + /// capturing them all over the place all the time. + /// + /// - If you want panics and errors to both have backtraces, set + /// `RUST_BACKTRACE=1`; + /// - If you want only errors to have backtraces, set + /// `RUST_LIB_BACKTRACE=1`; + /// - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and + /// `RUST_LIB_BACKTRACE=0`. + /// + /// [tracking]: https://github.com/rust-lang/rust/issues/53487 + #[cfg(backtrace)] + pub fn backtrace(&self) -> &Backtrace { + self.inner.backtrace() + } + + /// An iterator of the chain of source errors contained by this Error. + /// + /// This iterator will visit every error in the cause chain of this error + /// object, beginning with the error that this error object was created + /// from. + /// + /// # Example + /// + /// ``` + /// use anyhow::Error; + /// use std::io; + /// + /// pub fn underlying_io_error_kind(error: &Error) -> Option { + /// for cause in error.chain() { + /// if let Some(io_error) = cause.downcast_ref::() { + /// return Some(io_error.kind()); + /// } + /// } + /// None + /// } + /// ``` + #[cfg(feature = "std")] + pub fn chain(&self) -> Chain { + self.inner.chain() + } + + /// The lowest level cause of this error — this error's cause's + /// cause's cause etc. + /// + /// The root cause is the last error in the iterator produced by + /// [`chain()`][Error::chain]. + #[cfg(feature = "std")] + pub fn root_cause(&self) -> &(dyn StdError + 'static) { + let mut chain = self.chain(); + let mut root_cause = chain.next().unwrap(); + for cause in chain { + root_cause = cause; + } + root_cause + } + + /// Returns true if `E` is the type held by this error object. + /// + /// For errors with context, this method returns true if `E` matches the + /// type of the context `C` **or** the type of the error on which the + /// context has been attached. For details about the interaction between + /// context and downcasting, [see here]. + /// + /// [see here]: trait.Context.html#effect-on-downcasting + pub fn is(&self) -> bool + where + E: Display + Debug + Send + Sync + 'static, + { + self.downcast_ref::().is_some() + } + + /// Attempt to downcast the error object to a concrete type. + pub fn downcast(self) -> Result + where + E: Display + Debug + Send + Sync + 'static, + { + let target = TypeId::of::(); + unsafe { + // Use vtable to find NonNull<()> which points to a value of type E + // somewhere inside the data structure. + let addr = match (self.inner.vtable.object_downcast)(&self.inner, target) { + Some(addr) => addr, + None => return Err(self), + }; + + // Prepare to read E out of the data structure. We'll drop the rest + // of the data structure separately so that E is not dropped. + let outer = ManuallyDrop::new(self); + + // Read E from where the vtable found it. + let error = ptr::read(addr.cast::().as_ptr()); + + // Read Box> from self. Can't move it out because + // Error has a Drop impl which we want to not run. + let inner = ptr::read(&outer.inner); + let erased = ManuallyDrop::into_inner(inner); + + // Drop rest of the data structure outside of E. + (erased.vtable.object_drop_rest)(erased, target); + + Ok(error) + } + } + + /// Downcast this error object by reference. + /// + /// # Example + /// + /// ``` + /// # use anyhow::anyhow; + /// # use std::fmt::{self, Display}; + /// # use std::task::Poll; + /// # + /// # #[derive(Debug)] + /// # enum DataStoreError { + /// # Censored(()), + /// # } + /// # + /// # impl Display for DataStoreError { + /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # impl std::error::Error for DataStoreError {} + /// # + /// # const REDACTED_CONTENT: () = (); + /// # + /// # let error = anyhow!("..."); + /// # let root_cause = &error; + /// # + /// # let ret = + /// // If the error was caused by redaction, then return a tombstone instead + /// // of the content. + /// match root_cause.downcast_ref::() { + /// Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), + /// None => Err(error), + /// } + /// # ; + /// ``` + pub fn downcast_ref(&self) -> Option<&E> + where + E: Display + Debug + Send + Sync + 'static, + { + let target = TypeId::of::(); + unsafe { + // Use vtable to find NonNull<()> which points to a value of type E + // somewhere inside the data structure. + let addr = (self.inner.vtable.object_downcast)(&self.inner, target)?; + Some(&*addr.cast::().as_ptr()) + } + } + + /// Downcast this error object by mutable reference. + pub fn downcast_mut(&mut self) -> Option<&mut E> + where + E: Display + Debug + Send + Sync + 'static, + { + let target = TypeId::of::(); + unsafe { + // Use vtable to find NonNull<()> which points to a value of type E + // somewhere inside the data structure. + let addr = (self.inner.vtable.object_downcast)(&self.inner, target)?; + Some(&mut *addr.cast::().as_ptr()) + } + } +} + +#[cfg(feature = "std")] +impl From for Error +where + E: StdError + Send + Sync + 'static, +{ + fn from(error: E) -> Self { + let backtrace = backtrace_if_absent!(error); + Error::from_std(error, backtrace) + } +} + +#[cfg(feature = "std")] +impl Deref for Error { + type Target = dyn StdError + Send + Sync + 'static; + + fn deref(&self) -> &Self::Target { + self.inner.error() + } +} + +#[cfg(feature = "std")] +impl DerefMut for Error { + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner.error_mut() + } +} + +impl Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.inner.display(formatter) + } +} + +impl Debug for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.inner.debug(formatter) + } +} + +impl Drop for Error { + fn drop(&mut self) { + unsafe { + // Read Box> from self. + let inner = ptr::read(&self.inner); + let erased = ManuallyDrop::into_inner(inner); + + // Invoke the vtable's drop behavior. + (erased.vtable.object_drop)(erased); + } + } +} + +struct ErrorVTable { + object_drop: unsafe fn(Box>), + object_ref: unsafe fn(&ErrorImpl<()>) -> &(dyn StdError + Send + Sync + 'static), + #[cfg(feature = "std")] + object_mut: unsafe fn(&mut ErrorImpl<()>) -> &mut (dyn StdError + Send + Sync + 'static), + object_boxed: unsafe fn(Box>) -> Box, + object_downcast: unsafe fn(&ErrorImpl<()>, TypeId) -> Option>, + object_drop_rest: unsafe fn(Box>, TypeId), +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_drop(e: Box>) { + // Cast back to ErrorImpl so that the allocator receives the correct + // Layout to deallocate the Box's memory. + let unerased = mem::transmute::>, Box>>(e); + drop(unerased); +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_drop_front(e: Box>, target: TypeId) { + // Drop the fields of ErrorImpl other than E as well as the Box allocation, + // without dropping E itself. This is used by downcast after doing a + // ptr::read to take ownership of the E. + let _ = target; + let unerased = mem::transmute::>, Box>>>(e); + drop(unerased); +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_ref(e: &ErrorImpl<()>) -> &(dyn StdError + Send + Sync + 'static) +where + E: StdError + Send + Sync + 'static, +{ + // Attach E's native StdError vtable onto a pointer to self._object. + &(*(e as *const ErrorImpl<()> as *const ErrorImpl))._object +} + +// Safety: requires layout of *e to match ErrorImpl. +#[cfg(feature = "std")] +unsafe fn object_mut(e: &mut ErrorImpl<()>) -> &mut (dyn StdError + Send + Sync + 'static) +where + E: StdError + Send + Sync + 'static, +{ + // Attach E's native StdError vtable onto a pointer to self._object. + &mut (*(e as *mut ErrorImpl<()> as *mut ErrorImpl))._object +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_boxed(e: Box>) -> Box +where + E: StdError + Send + Sync + 'static, +{ + // Attach ErrorImpl's native StdError vtable. The StdError impl is below. + mem::transmute::>, Box>>(e) +} + +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_downcast(e: &ErrorImpl<()>, target: TypeId) -> Option> +where + E: 'static, +{ + if TypeId::of::() == target { + // Caller is looking for an E pointer and e is ErrorImpl, take a + // pointer to its E field. + let unerased = e as *const ErrorImpl<()> as *const ErrorImpl; + let addr = &(*unerased)._object as *const E as *mut (); + Some(NonNull::new_unchecked(addr)) + } else { + None + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +#[cfg(feature = "std")] +unsafe fn context_downcast(e: &ErrorImpl<()>, target: TypeId) -> Option> +where + C: 'static, + E: 'static, +{ + if TypeId::of::() == target { + let unerased = e as *const ErrorImpl<()> as *const ErrorImpl>; + let addr = &(*unerased)._object.context as *const C as *mut (); + Some(NonNull::new_unchecked(addr)) + } else if TypeId::of::() == target { + let unerased = e as *const ErrorImpl<()> as *const ErrorImpl>; + let addr = &(*unerased)._object.error as *const E as *mut (); + Some(NonNull::new_unchecked(addr)) + } else { + None + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +#[cfg(feature = "std")] +unsafe fn context_drop_rest(e: Box>, target: TypeId) +where + C: 'static, + E: 'static, +{ + // Called after downcasting by value to either the C or the E and doing a + // ptr::read to take ownership of that value. + if TypeId::of::() == target { + let unerased = mem::transmute::< + Box>, + Box, E>>>, + >(e); + drop(unerased); + } else { + let unerased = mem::transmute::< + Box>, + Box>>>, + >(e); + drop(unerased); + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +unsafe fn context_chain_downcast(e: &ErrorImpl<()>, target: TypeId) -> Option> +where + C: 'static, +{ + if TypeId::of::() == target { + let unerased = e as *const ErrorImpl<()> as *const ErrorImpl>; + let addr = &(*unerased)._object.context as *const C as *mut (); + Some(NonNull::new_unchecked(addr)) + } else { + // Recurse down the context chain per the inner error's vtable. + let unerased = e as *const ErrorImpl<()> as *const ErrorImpl>; + let source = &(*unerased)._object.error; + (source.inner.vtable.object_downcast)(&source.inner, target) + } +} + +// Safety: requires layout of *e to match ErrorImpl>. +unsafe fn context_chain_drop_rest(e: Box>, target: TypeId) +where + C: 'static, +{ + // Called after downcasting by value to either the C or one of the causes + // and doing a ptr::read to take ownership of that value. + if TypeId::of::() == target { + let unerased = mem::transmute::< + Box>, + Box, Error>>>, + >(e); + // Drop the entire rest of the data structure rooted in the next Error. + drop(unerased); + } else { + let unerased = mem::transmute::< + Box>, + Box>>>, + >(e); + // Read out a ManuallyDrop>> from the next error. + let inner = ptr::read(&unerased._object.error.inner); + drop(unerased); + let erased = ManuallyDrop::into_inner(inner); + // Recursively drop the next error using the same target typeid. + (erased.vtable.object_drop_rest)(erased, target); + } +} + +// repr C to ensure that E remains in the final position. +#[repr(C)] +pub(crate) struct ErrorImpl { + vtable: &'static ErrorVTable, + backtrace: Option, + // NOTE: Don't use directly. Use only through vtable. Erased type may have + // different alignment. + _object: E, +} + +// repr C to ensure that ContextError has the same layout as +// ContextError, E> and ContextError>. +#[repr(C)] +pub(crate) struct ContextError { + pub context: C, + pub error: E, +} + +impl ErrorImpl { + fn erase(&self) -> &ErrorImpl<()> { + // Erase the concrete type of E but preserve the vtable in self.vtable + // for manipulating the resulting thin pointer. This is analogous to an + // unsize coersion. + unsafe { &*(self as *const ErrorImpl as *const ErrorImpl<()>) } + } +} + +impl ErrorImpl<()> { + pub(crate) fn error(&self) -> &(dyn StdError + Send + Sync + 'static) { + // Use vtable to attach E's native StdError vtable for the right + // original type E. + unsafe { &*(self.vtable.object_ref)(self) } + } + + #[cfg(feature = "std")] + pub(crate) fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) { + // Use vtable to attach E's native StdError vtable for the right + // original type E. + unsafe { &mut *(self.vtable.object_mut)(self) } + } + + #[cfg(backtrace)] + pub(crate) fn backtrace(&self) -> &Backtrace { + // This unwrap can only panic if the underlying error's backtrace method + // is nondeterministic, which would only happen in maliciously + // constructed code. + self.backtrace + .as_ref() + .or_else(|| self.error().backtrace()) + .expect("backtrace capture failed") + } + + pub(crate) fn chain(&self) -> Chain { + Chain::new(self.error()) + } +} + +impl StdError for ErrorImpl +where + E: StdError, +{ + #[cfg(backtrace)] + fn backtrace(&self) -> Option<&Backtrace> { + Some(self.erase().backtrace()) + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.erase().error().source() + } +} + +impl Debug for ErrorImpl +where + E: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.erase().debug(formatter) + } +} + +impl Display for ErrorImpl +where + E: Display, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.erase().error(), formatter) + } +} + +impl From for Box { + fn from(error: Error) -> Self { + let outer = ManuallyDrop::new(error); + unsafe { + // Read Box> from error. Can't move it out because + // Error has a Drop impl which we want to not run. + let inner = ptr::read(&outer.inner); + let erased = ManuallyDrop::into_inner(inner); + + // Use vtable to attach ErrorImpl's native StdError vtable for + // the right original type E. + (erased.vtable.object_boxed)(erased) + } + } +} + +impl From for Box { + fn from(error: Error) -> Self { + Box::::from(error) + } +} + +#[cfg(feature = "std")] +impl AsRef for Error { + fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) { + &**self + } +} + +#[cfg(feature = "std")] +impl AsRef for Error { + fn as_ref(&self) -> &(dyn StdError + 'static) { + &**self + } +} diff --git a/src/rust/vendor/anyhow/src/fmt.rs b/src/rust/vendor/anyhow/src/fmt.rs new file mode 100644 index 000000000..be93e1a65 --- /dev/null +++ b/src/rust/vendor/anyhow/src/fmt.rs @@ -0,0 +1,154 @@ +use crate::chain::Chain; +use crate::error::ErrorImpl; +use core::fmt::{self, Debug, Write}; + +impl ErrorImpl<()> { + pub(crate) fn display(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.error())?; + + if f.alternate() { + for cause in self.chain().skip(1) { + write!(f, ": {}", cause)?; + } + } + + Ok(()) + } + + pub(crate) fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result { + let error = self.error(); + + if f.alternate() { + return Debug::fmt(error, f); + } + + write!(f, "{}", error)?; + + if let Some(cause) = error.source() { + write!(f, "\n\nCaused by:")?; + let multiple = cause.source().is_some(); + for (n, error) in Chain::new(cause).enumerate() { + writeln!(f)?; + let mut indented = Indented { + inner: f, + number: if multiple { Some(n) } else { None }, + started: false, + }; + write!(indented, "{}", error)?; + } + } + + #[cfg(backtrace)] + { + use std::backtrace::BacktraceStatus; + + let backtrace = self.backtrace(); + if let BacktraceStatus::Captured = backtrace.status() { + let mut backtrace = backtrace.to_string(); + write!(f, "\n\n")?; + if backtrace.starts_with("stack backtrace:") { + // Capitalize to match "Caused by:" + backtrace.replace_range(0..1, "S"); + } else { + // "stack backtrace:" prefix was removed in + // https://github.com/rust-lang/backtrace-rs/pull/286 + writeln!(f, "Stack backtrace:")?; + } + backtrace.truncate(backtrace.trim_end().len()); + write!(f, "{}", backtrace)?; + } + } + + Ok(()) + } +} + +struct Indented<'a, D> { + inner: &'a mut D, + number: Option, + started: bool, +} + +impl Write for Indented<'_, T> +where + T: Write, +{ + fn write_str(&mut self, s: &str) -> fmt::Result { + for (i, line) in s.split('\n').enumerate() { + if !self.started { + self.started = true; + match self.number { + Some(number) => write!(self.inner, "{: >5}: ", number)?, + None => self.inner.write_str(" ")?, + } + } else if i > 0 { + self.inner.write_char('\n')?; + if self.number.is_some() { + self.inner.write_str(" ")?; + } else { + self.inner.write_str(" ")?; + } + } + + self.inner.write_str(line)?; + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn one_digit() { + let input = "verify\nthis"; + let expected = " 2: verify\n this"; + let mut output = String::new(); + + Indented { + inner: &mut output, + number: Some(2), + started: false, + } + .write_str(input) + .unwrap(); + + assert_eq!(expected, output); + } + + #[test] + fn two_digits() { + let input = "verify\nthis"; + let expected = " 12: verify\n this"; + let mut output = String::new(); + + Indented { + inner: &mut output, + number: Some(12), + started: false, + } + .write_str(input) + .unwrap(); + + assert_eq!(expected, output); + } + + #[test] + fn no_digits() { + let input = "verify\nthis"; + let expected = " verify\n this"; + let mut output = String::new(); + + Indented { + inner: &mut output, + number: None, + started: false, + } + .write_str(input) + .unwrap(); + + assert_eq!(expected, output); + } +} diff --git a/src/rust/vendor/anyhow/src/kind.rs b/src/rust/vendor/anyhow/src/kind.rs new file mode 100644 index 000000000..fdeb060ad --- /dev/null +++ b/src/rust/vendor/anyhow/src/kind.rs @@ -0,0 +1,116 @@ +// Tagged dispatch mechanism for resolving the behavior of `anyhow!($expr)`. +// +// When anyhow! is given a single expr argument to turn into anyhow::Error, we +// want the resulting Error to pick up the input's implementation of source() +// and backtrace() if it has a std::error::Error impl, otherwise require nothing +// more than Display and Debug. +// +// Expressed in terms of specialization, we want something like: +// +// trait AnyhowNew { +// fn new(self) -> Error; +// } +// +// impl AnyhowNew for T +// where +// T: Display + Debug + Send + Sync + 'static, +// { +// default fn new(self) -> Error { +// /* no std error impl */ +// } +// } +// +// impl AnyhowNew for T +// where +// T: std::error::Error + Send + Sync + 'static, +// { +// fn new(self) -> Error { +// /* use std error's source() and backtrace() */ +// } +// } +// +// Since specialization is not stable yet, instead we rely on autoref behavior +// of method resolution to perform tagged dispatch. Here we have two traits +// AdhocKind and TraitKind that both have an anyhow_kind() method. AdhocKind is +// implemented whether or not the caller's type has a std error impl, while +// TraitKind is implemented only when a std error impl does exist. The ambiguity +// is resolved by AdhocKind requiring an extra autoref so that it has lower +// precedence. +// +// The anyhow! macro will set up the call in this form: +// +// #[allow(unused_imports)] +// use $crate::private::{AdhocKind, TraitKind}; +// let error = $msg; +// (&error).anyhow_kind().new(error) + +use crate::Error; +use core::fmt::{Debug, Display}; + +#[cfg(feature = "std")] +use crate::StdError; + +#[cfg(backtrace)] +use std::backtrace::Backtrace; + +pub struct Adhoc; + +pub trait AdhocKind: Sized { + #[inline] + fn anyhow_kind(&self) -> Adhoc { + Adhoc + } +} + +impl AdhocKind for &T where T: ?Sized + Display + Debug + Send + Sync + 'static {} + +impl Adhoc { + pub fn new(self, message: M) -> Error + where + M: Display + Debug + Send + Sync + 'static, + { + Error::from_adhoc(message, backtrace!()) + } +} + +pub struct Trait; + +pub trait TraitKind: Sized { + #[inline] + fn anyhow_kind(&self) -> Trait { + Trait + } +} + +impl TraitKind for E where E: Into {} + +impl Trait { + pub fn new(self, error: E) -> Error + where + E: Into, + { + error.into() + } +} + +#[cfg(feature = "std")] +pub struct Boxed; + +#[cfg(feature = "std")] +pub trait BoxedKind: Sized { + #[inline] + fn anyhow_kind(&self) -> Boxed { + Boxed + } +} + +#[cfg(feature = "std")] +impl BoxedKind for Box {} + +#[cfg(feature = "std")] +impl Boxed { + pub fn new(self, error: Box) -> Error { + let backtrace = backtrace_if_absent!(error); + Error::from_boxed(error, backtrace) + } +} diff --git a/src/rust/vendor/anyhow/src/lib.rs b/src/rust/vendor/anyhow/src/lib.rs new file mode 100644 index 000000000..684c1ab43 --- /dev/null +++ b/src/rust/vendor/anyhow/src/lib.rs @@ -0,0 +1,612 @@ +//! [![github]](https://github.com/dtolnay/anyhow) [![crates-io]](https://crates.io/crates/anyhow) [![docs-rs]](https://docs.rs/anyhow) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K +//! +//!
+//! +//! This library provides [`anyhow::Error`][Error], a trait object based error +//! type for easy idiomatic error handling in Rust applications. +//! +//!
+//! +//! # Details +//! +//! - Use `Result`, or equivalently `anyhow::Result`, as +//! the return type of any fallible function. +//! +//! Within the function, use `?` to easily propagate any error that implements +//! the `std::error::Error` trait. +//! +//! ``` +//! # pub trait Deserialize {} +//! # +//! # mod serde_json { +//! # use super::Deserialize; +//! # use std::io; +//! # +//! # pub fn from_str(json: &str) -> io::Result { +//! # unimplemented!() +//! # } +//! # } +//! # +//! # struct ClusterMap; +//! # +//! # impl Deserialize for ClusterMap {} +//! # +//! use anyhow::Result; +//! +//! fn get_cluster_info() -> Result { +//! let config = std::fs::read_to_string("cluster.json")?; +//! let map: ClusterMap = serde_json::from_str(&config)?; +//! Ok(map) +//! } +//! # +//! # fn main() {} +//! ``` +//! +//! - Attach context to help the person troubleshooting the error understand +//! where things went wrong. A low-level error like "No such file or +//! directory" can be annoying to debug without more context about what higher +//! level step the application was in the middle of. +//! +//! ``` +//! # struct It; +//! # +//! # impl It { +//! # fn detach(&self) -> Result<()> { +//! # unimplemented!() +//! # } +//! # } +//! # +//! use anyhow::{Context, Result}; +//! +//! fn main() -> Result<()> { +//! # return Ok(()); +//! # +//! # const _: &str = stringify! { +//! ... +//! # }; +//! # +//! # let it = It; +//! # let path = "./path/to/instrs.json"; +//! # +//! it.detach().context("Failed to detach the important thing")?; +//! +//! let content = std::fs::read(path) +//! .with_context(|| format!("Failed to read instrs from {}", path))?; +//! # +//! # const _: &str = stringify! { +//! ... +//! # }; +//! # +//! # Ok(()) +//! } +//! ``` +//! +//! ```console +//! Error: Failed to read instrs from ./path/to/instrs.json +//! +//! Caused by: +//! No such file or directory (os error 2) +//! ``` +//! +//! - Downcasting is supported and can be by value, by shared reference, or by +//! mutable reference as needed. +//! +//! ``` +//! # use anyhow::anyhow; +//! # use std::fmt::{self, Display}; +//! # use std::task::Poll; +//! # +//! # #[derive(Debug)] +//! # enum DataStoreError { +//! # Censored(()), +//! # } +//! # +//! # impl Display for DataStoreError { +//! # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +//! # unimplemented!() +//! # } +//! # } +//! # +//! # impl std::error::Error for DataStoreError {} +//! # +//! # const REDACTED_CONTENT: () = (); +//! # +//! # let error = anyhow!("..."); +//! # let root_cause = &error; +//! # +//! # let ret = +//! // If the error was caused by redaction, then return a +//! // tombstone instead of the content. +//! match root_cause.downcast_ref::() { +//! Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), +//! None => Err(error), +//! } +//! # ; +//! ``` +//! +//! - If using the nightly channel, a backtrace is captured and printed with the +//! error if the underlying error type does not already provide its own. In +//! order to see backtraces, they must be enabled through the environment +//! variables described in [`std::backtrace`]: +//! +//! - If you want panics and errors to both have backtraces, set +//! `RUST_BACKTRACE=1`; +//! - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; +//! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and +//! `RUST_LIB_BACKTRACE=0`. +//! +//! The tracking issue for this feature is [rust-lang/rust#53487]. +//! +//! [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables +//! [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487 +//! +//! - Anyhow works with any error type that has an impl of `std::error::Error`, +//! including ones defined in your crate. We do not bundle a `derive(Error)` +//! macro but you can write the impls yourself or use a standalone macro like +//! [thiserror]. +//! +//! [thiserror]: https://github.com/dtolnay/thiserror +//! +//! ``` +//! use thiserror::Error; +//! +//! #[derive(Error, Debug)] +//! pub enum FormatError { +//! #[error("Invalid header (expected {expected:?}, got {found:?})")] +//! InvalidHeader { +//! expected: String, +//! found: String, +//! }, +//! #[error("Missing attribute: {0}")] +//! MissingAttribute(String), +//! } +//! ``` +//! +//! - One-off error messages can be constructed using the `anyhow!` macro, which +//! supports string interpolation and produces an `anyhow::Error`. +//! +//! ``` +//! # use anyhow::{anyhow, Result}; +//! # +//! # fn demo() -> Result<()> { +//! # let missing = "..."; +//! return Err(anyhow!("Missing attribute: {}", missing)); +//! # Ok(()) +//! # } +//! ``` +//! +//!
+//! +//! # No-std support +//! +//! In no_std mode, the same API is almost all available and works the same way. +//! To depend on Anyhow in no_std mode, disable our default enabled "std" +//! feature in Cargo.toml. A global allocator is required. +//! +//! ```toml +//! [dependencies] +//! anyhow = { version = "1.0", default-features = false } +//! ``` +//! +//! Since the `?`-based error conversions would normally rely on the +//! `std::error::Error` trait which is only available through std, no_std mode +//! will require an explicit `.map_err(Error::msg)` when working with a +//! non-Anyhow error type inside a function that returns Anyhow's error type. + +#![doc(html_root_url = "https://docs.rs/anyhow/1.0.31")] +#![cfg_attr(backtrace, feature(backtrace))] +#![cfg_attr(doc_cfg, feature(doc_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] +#![allow( + clippy::needless_doctest_main, + clippy::new_ret_no_self, + clippy::wrong_self_convention +)] + +mod alloc { + #[cfg(not(feature = "std"))] + extern crate alloc; + + #[cfg(not(feature = "std"))] + pub use alloc::boxed::Box; + + #[cfg(feature = "std")] + pub use std::boxed::Box; +} + +#[macro_use] +mod backtrace; +mod chain; +mod context; +mod error; +mod fmt; +mod kind; +mod macros; +mod wrapper; + +use crate::alloc::Box; +use crate::error::ErrorImpl; +use core::fmt::Display; +use core::mem::ManuallyDrop; + +#[cfg(not(feature = "std"))] +use core::fmt::Debug; + +#[cfg(feature = "std")] +use std::error::Error as StdError; + +#[cfg(not(feature = "std"))] +trait StdError: Debug + Display { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + None + } +} + +pub use anyhow as format_err; + +/// The `Error` type, a wrapper around a dynamic error type. +/// +/// `Error` works a lot like `Box`, but with these +/// differences: +/// +/// - `Error` requires that the error is `Send`, `Sync`, and `'static`. +/// - `Error` guarantees that a backtrace is available, even if the underlying +/// error type does not provide one. +/// - `Error` is represented as a narrow pointer — exactly one word in +/// size instead of two. +/// +///
+/// +/// # Display representations +/// +/// When you print an error object using "{}" or to_string(), only the outermost +/// underlying error or context is printed, not any of the lower level causes. +/// This is exactly as if you had called the Display impl of the error from +/// which you constructed your anyhow::Error. +/// +/// ```console +/// Failed to read instrs from ./path/to/instrs.json +/// ``` +/// +/// To print causes as well using anyhow's default formatting of causes, use the +/// alternate selector "{:#}". +/// +/// ```console +/// Failed to read instrs from ./path/to/instrs.json: No such file or directory (os error 2) +/// ``` +/// +/// The Debug format "{:?}" includes your backtrace if one was captured. Note +/// that this is the representation you get by default if you return an error +/// from `fn main` instead of printing it explicitly yourself. +/// +/// ```console +/// Error: Failed to read instrs from ./path/to/instrs.json +/// +/// Caused by: +/// No such file or directory (os error 2) +/// ``` +/// +/// and if there is a backtrace available: +/// +/// ```console +/// Error: Failed to read instrs from ./path/to/instrs.json +/// +/// Caused by: +/// No such file or directory (os error 2) +/// +/// Stack backtrace: +/// 0: ::ext_context +/// at /git/anyhow/src/backtrace.rs:26 +/// 1: core::result::Result::map_err +/// at /git/rustc/src/libcore/result.rs:596 +/// 2: anyhow::context:: for core::result::Result>::with_context +/// at /git/anyhow/src/context.rs:58 +/// 3: testing::main +/// at src/main.rs:5 +/// 4: std::rt::lang_start +/// at /git/rustc/src/libstd/rt.rs:61 +/// 5: main +/// 6: __libc_start_main +/// 7: _start +/// ``` +/// +/// To see a conventional struct-style Debug representation, use "{:#?}". +/// +/// ```console +/// Error { +/// context: "Failed to read instrs from ./path/to/instrs.json", +/// source: Os { +/// code: 2, +/// kind: NotFound, +/// message: "No such file or directory", +/// }, +/// } +/// ``` +/// +/// If none of the built-in representations are appropriate and you would prefer +/// to render the error and its cause chain yourself, it can be done something +/// like this: +/// +/// ``` +/// use anyhow::{Context, Result}; +/// +/// fn main() { +/// if let Err(err) = try_main() { +/// eprintln!("ERROR: {}", err); +/// err.chain().skip(1).for_each(|cause| eprintln!("because: {}", cause)); +/// std::process::exit(1); +/// } +/// } +/// +/// fn try_main() -> Result<()> { +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # Ok(()) +/// } +/// ``` +pub struct Error { + inner: ManuallyDrop>>, +} + +/// Iterator of a chain of source errors. +/// +/// This type is the iterator returned by [`Error::chain`]. +/// +/// # Example +/// +/// ``` +/// use anyhow::Error; +/// use std::io; +/// +/// pub fn underlying_io_error_kind(error: &Error) -> Option { +/// for cause in error.chain() { +/// if let Some(io_error) = cause.downcast_ref::() { +/// return Some(io_error.kind()); +/// } +/// } +/// None +/// } +/// ``` +#[cfg(feature = "std")] +#[derive(Clone)] +pub struct Chain<'a> { + state: crate::chain::ChainState<'a>, +} + +/// `Result` +/// +/// This is a reasonable return type to use throughout your application but also +/// for `fn main`; if you do, failures will be printed along with any +/// [context][Context] and a backtrace if one was captured. +/// +/// `anyhow::Result` may be used with one *or* two type parameters. +/// +/// ```rust +/// use anyhow::Result; +/// +/// # const IGNORE: &str = stringify! { +/// fn demo1() -> Result {...} +/// // ^ equivalent to std::result::Result +/// +/// fn demo2() -> Result {...} +/// // ^ equivalent to std::result::Result +/// # }; +/// ``` +/// +/// # Example +/// +/// ``` +/// # pub trait Deserialize {} +/// # +/// # mod serde_json { +/// # use super::Deserialize; +/// # use std::io; +/// # +/// # pub fn from_str(json: &str) -> io::Result { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # #[derive(Debug)] +/// # struct ClusterMap; +/// # +/// # impl Deserialize for ClusterMap {} +/// # +/// use anyhow::Result; +/// +/// fn main() -> Result<()> { +/// # return Ok(()); +/// let config = std::fs::read_to_string("cluster.json")?; +/// let map: ClusterMap = serde_json::from_str(&config)?; +/// println!("cluster info: {:#?}", map); +/// Ok(()) +/// } +/// ``` +pub type Result = core::result::Result; + +/// Provides the `context` method for `Result`. +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `anyhow`. +/// +///
+/// +/// # Example +/// +/// ``` +/// use anyhow::{Context, Result}; +/// use std::fs; +/// use std::path::PathBuf; +/// +/// pub struct ImportantThing { +/// path: PathBuf, +/// } +/// +/// impl ImportantThing { +/// # const IGNORE: &'static str = stringify! { +/// pub fn detach(&mut self) -> Result<()> {...} +/// # }; +/// # fn detach(&mut self) -> Result<()> { +/// # unimplemented!() +/// # } +/// } +/// +/// pub fn do_it(mut it: ImportantThing) -> Result> { +/// it.detach().context("Failed to detach the important thing")?; +/// +/// let path = &it.path; +/// let content = fs::read(path) +/// .with_context(|| format!("Failed to read instrs from {}", path.display()))?; +/// +/// Ok(content) +/// } +/// ``` +/// +/// When printed, the outermost context would be printed first and the lower +/// level underlying causes would be enumerated below. +/// +/// ```console +/// Error: Failed to read instrs from ./path/to/instrs.json +/// +/// Caused by: +/// No such file or directory (os error 2) +/// ``` +/// +///
+/// +/// # Effect on downcasting +/// +/// After attaching context of type `C` onto an error of type `E`, the resulting +/// `anyhow::Error` may be downcast to `C` **or** to `E`. +/// +/// That is, in codebases that rely on downcasting, Anyhow's context supports +/// both of the following use cases: +/// +/// - **Attaching context whose type is insignificant onto errors whose type +/// is used in downcasts.** +/// +/// In other error libraries whose context is not designed this way, it can +/// be risky to introduce context to existing code because new context might +/// break existing working downcasts. In Anyhow, any downcast that worked +/// before adding context will continue to work after you add a context, so +/// you should freely add human-readable context to errors wherever it would +/// be helpful. +/// +/// ``` +/// # use anyhow::bail; +/// # use thiserror::Error; +/// # +/// # #[derive(Error, Debug)] +/// # #[error("???")] +/// # struct SuspiciousError; +/// # +/// # fn helper() -> Result<()> { +/// # bail!(SuspiciousError); +/// # } +/// # +/// use anyhow::{Context, Result}; +/// +/// fn do_it() -> Result<()> { +/// helper().context("Failed to complete the work")?; +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # unreachable!() +/// } +/// +/// fn main() { +/// let err = do_it().unwrap_err(); +/// if let Some(e) = err.downcast_ref::() { +/// // If helper() returned SuspiciousError, this downcast will +/// // correctly succeed even with the context in between. +/// # return; +/// } +/// # panic!("expected downcast to succeed"); +/// } +/// ``` +/// +/// - **Attaching context whose type is used in downcasts onto errors whose +/// type is insignificant.** +/// +/// Some codebases prefer to use machine-readable context to categorize +/// lower level errors in a way that will be actionable to higher levels of +/// the application. +/// +/// ``` +/// # use anyhow::bail; +/// # use thiserror::Error; +/// # +/// # #[derive(Error, Debug)] +/// # #[error("???")] +/// # struct HelperFailed; +/// # +/// # fn helper() -> Result<()> { +/// # bail!("no such file or directory"); +/// # } +/// # +/// use anyhow::{Context, Result}; +/// +/// fn do_it() -> Result<()> { +/// helper().context(HelperFailed)?; +/// # const IGNORE: &str = stringify! { +/// ... +/// # }; +/// # unreachable!() +/// } +/// +/// fn main() { +/// let err = do_it().unwrap_err(); +/// if let Some(e) = err.downcast_ref::() { +/// // If helper failed, this downcast will succeed because +/// // HelperFailed is the context that has been attached to +/// // that error. +/// # return; +/// } +/// # panic!("expected downcast to succeed"); +/// } +/// ``` +pub trait Context: context::private::Sealed { + /// Wrap the error value with additional context. + fn context(self, context: C) -> Result + where + C: Display + Send + Sync + 'static; + + /// Wrap the error value with additional context that is evaluated lazily + /// only once an error does occur. + fn with_context(self, f: F) -> Result + where + C: Display + Send + Sync + 'static, + F: FnOnce() -> C; +} + +// Not public API. Referenced by macro-generated code. +#[doc(hidden)] +pub mod private { + use crate::Error; + use core::fmt::{Debug, Display}; + + #[cfg(backtrace)] + use std::backtrace::Backtrace; + + pub use core::result::Result::Err; + + #[doc(hidden)] + pub mod kind { + pub use crate::kind::{AdhocKind, TraitKind}; + + #[cfg(feature = "std")] + pub use crate::kind::BoxedKind; + } + + pub fn new_adhoc(message: M) -> Error + where + M: Display + Debug + Send + Sync + 'static, + { + Error::from_adhoc(message, backtrace!()) + } +} diff --git a/src/rust/vendor/anyhow/src/macros.rs b/src/rust/vendor/anyhow/src/macros.rs new file mode 100644 index 000000000..15a920810 --- /dev/null +++ b/src/rust/vendor/anyhow/src/macros.rs @@ -0,0 +1,163 @@ +/// Return early with an error. +/// +/// This macro is equivalent to `return Err(From::from($err))`. +/// +/// # Example +/// +/// ``` +/// # use anyhow::{bail, Result}; +/// # +/// # fn has_permission(user: usize, resource: usize) -> bool { +/// # true +/// # } +/// # +/// # fn main() -> Result<()> { +/// # let user = 0; +/// # let resource = 0; +/// # +/// if !has_permission(user, resource) { +/// bail!("permission denied for accessing {}", resource); +/// } +/// # Ok(()) +/// # } +/// ``` +/// +/// ``` +/// # use anyhow::{bail, Result}; +/// # use thiserror::Error; +/// # +/// # const MAX_DEPTH: usize = 1; +/// # +/// #[derive(Error, Debug)] +/// enum ScienceError { +/// #[error("recursion limit exceeded")] +/// RecursionLimitExceeded, +/// # #[error("...")] +/// # More = (stringify! { +/// ... +/// # }, 1).1, +/// } +/// +/// # fn main() -> Result<()> { +/// # let depth = 0; +/// # +/// if depth > MAX_DEPTH { +/// bail!(ScienceError::RecursionLimitExceeded); +/// } +/// # Ok(()) +/// # } +/// ``` +#[macro_export] +macro_rules! bail { + ($msg:literal $(,)?) => { + return $crate::private::Err($crate::anyhow!($msg)); + }; + ($err:expr $(,)?) => { + return $crate::private::Err($crate::anyhow!($err)); + }; + ($fmt:expr, $($arg:tt)*) => { + return $crate::private::Err($crate::anyhow!($fmt, $($arg)*)); + }; +} + +/// Return early with an error if a condition is not satisfied. +/// +/// This macro is equivalent to `if !$cond { return Err(From::from($err)); }`. +/// +/// Analogously to `assert!`, `ensure!` takes a condition and exits the function +/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error` +/// rather than panicking. +/// +/// # Example +/// +/// ``` +/// # use anyhow::{ensure, Result}; +/// # +/// # fn main() -> Result<()> { +/// # let user = 0; +/// # +/// ensure!(user == 0, "only user 0 is allowed"); +/// # Ok(()) +/// # } +/// ``` +/// +/// ``` +/// # use anyhow::{ensure, Result}; +/// # use thiserror::Error; +/// # +/// # const MAX_DEPTH: usize = 1; +/// # +/// #[derive(Error, Debug)] +/// enum ScienceError { +/// #[error("recursion limit exceeded")] +/// RecursionLimitExceeded, +/// # #[error("...")] +/// # More = (stringify! { +/// ... +/// # }, 1).1, +/// } +/// +/// # fn main() -> Result<()> { +/// # let depth = 0; +/// # +/// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded); +/// # Ok(()) +/// # } +/// ``` +#[macro_export] +macro_rules! ensure { + ($cond:expr, $msg:literal $(,)?) => { + if !$cond { + return $crate::private::Err($crate::anyhow!($msg)); + } + }; + ($cond:expr, $err:expr $(,)?) => { + if !$cond { + return $crate::private::Err($crate::anyhow!($err)); + } + }; + ($cond:expr, $fmt:expr, $($arg:tt)*) => { + if !$cond { + return $crate::private::Err($crate::anyhow!($fmt, $($arg)*)); + } + }; +} + +/// Construct an ad-hoc error from a string. +/// +/// This evaluates to an `Error`. It can take either just a string, or a format +/// string with arguments. It also can take any custom type which implements +/// `Debug` and `Display`. +/// +/// # Example +/// +/// ``` +/// # type V = (); +/// # +/// use anyhow::{anyhow, Result}; +/// +/// fn lookup(key: &str) -> Result { +/// if key.len() != 16 { +/// return Err(anyhow!("key length must be 16 characters, got {:?}", key)); +/// } +/// +/// // ... +/// # Ok(()) +/// } +/// ``` +#[macro_export] +macro_rules! anyhow { + ($msg:literal $(,)?) => { + // Handle $:literal as a special case to make cargo-expanded code more + // concise in the common case. + $crate::private::new_adhoc($msg) + }; + ($err:expr $(,)?) => ({ + use $crate::private::kind::*; + let error = $err; + (&error).anyhow_kind().new(error) + }); + ($fmt:expr, $($arg:tt)*) => { + $crate::private::new_adhoc(format!($fmt, $($arg)*)) + }; +} diff --git a/src/rust/vendor/anyhow/src/wrapper.rs b/src/rust/vendor/anyhow/src/wrapper.rs new file mode 100644 index 000000000..3ebe51a88 --- /dev/null +++ b/src/rust/vendor/anyhow/src/wrapper.rs @@ -0,0 +1,78 @@ +use crate::StdError; +use core::fmt::{self, Debug, Display}; + +#[repr(transparent)] +pub struct MessageError(pub M); + +impl Debug for MessageError +where + M: Display + Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.0, f) + } +} + +impl Display for MessageError +where + M: Display + Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl StdError for MessageError where M: Display + Debug + 'static {} + +#[repr(transparent)] +pub struct DisplayError(pub M); + +impl Debug for DisplayError +where + M: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl Display for DisplayError +where + M: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl StdError for DisplayError where M: Display + 'static {} + +#[cfg(feature = "std")] +#[repr(transparent)] +pub struct BoxedError(pub Box); + +#[cfg(feature = "std")] +impl Debug for BoxedError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.0, f) + } +} + +#[cfg(feature = "std")] +impl Display for BoxedError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +#[cfg(feature = "std")] +impl StdError for BoxedError { + #[cfg(backtrace)] + fn backtrace(&self) -> Option<&crate::backtrace::Backtrace> { + self.0.backtrace() + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.0.source() + } +} diff --git a/src/rust/vendor/anyhow/tests/common/mod.rs b/src/rust/vendor/anyhow/tests/common/mod.rs new file mode 100644 index 000000000..fc165a5be --- /dev/null +++ b/src/rust/vendor/anyhow/tests/common/mod.rs @@ -0,0 +1,14 @@ +use anyhow::{bail, Result}; +use std::io; + +pub fn bail_literal() -> Result<()> { + bail!("oh no!"); +} + +pub fn bail_fmt() -> Result<()> { + bail!("{} {}!", "oh", "no"); +} + +pub fn bail_error() -> Result<()> { + bail!(io::Error::new(io::ErrorKind::Other, "oh no!")); +} diff --git a/src/rust/vendor/anyhow/tests/compiletest.rs b/src/rust/vendor/anyhow/tests/compiletest.rs new file mode 100644 index 000000000..f9aea23b5 --- /dev/null +++ b/src/rust/vendor/anyhow/tests/compiletest.rs @@ -0,0 +1,6 @@ +#[rustversion::attr(not(nightly), ignore)] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/src/rust/vendor/anyhow/tests/drop/mod.rs b/src/rust/vendor/anyhow/tests/drop/mod.rs new file mode 100644 index 000000000..c9d714447 --- /dev/null +++ b/src/rust/vendor/anyhow/tests/drop/mod.rs @@ -0,0 +1,52 @@ +use std::error::Error as StdError; +use std::fmt::{self, Display}; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering::SeqCst; +use std::sync::Arc; + +#[derive(Debug)] +pub struct Flag { + atomic: Arc, +} + +impl Flag { + pub fn new() -> Self { + Flag { + atomic: Arc::new(AtomicBool::new(false)), + } + } + + pub fn get(&self) -> bool { + self.atomic.load(SeqCst) + } +} + +#[derive(Debug)] +pub struct DetectDrop { + has_dropped: Flag, +} + +impl DetectDrop { + pub fn new(has_dropped: &Flag) -> Self { + DetectDrop { + has_dropped: Flag { + atomic: Arc::clone(&has_dropped.atomic), + }, + } + } +} + +impl StdError for DetectDrop {} + +impl Display for DetectDrop { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "oh no!") + } +} + +impl Drop for DetectDrop { + fn drop(&mut self) { + let already_dropped = self.has_dropped.atomic.swap(true, SeqCst); + assert!(!already_dropped); + } +} diff --git a/src/rust/vendor/anyhow/tests/test_autotrait.rs b/src/rust/vendor/anyhow/tests/test_autotrait.rs new file mode 100644 index 000000000..0c9326dad --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_autotrait.rs @@ -0,0 +1,13 @@ +use anyhow::Error; + +#[test] +fn test_send() { + fn assert_send() {} + assert_send::(); +} + +#[test] +fn test_sync() { + fn assert_sync() {} + assert_sync::(); +} diff --git a/src/rust/vendor/anyhow/tests/test_backtrace.rs b/src/rust/vendor/anyhow/tests/test_backtrace.rs new file mode 100644 index 000000000..ce385f501 --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_backtrace.rs @@ -0,0 +1,13 @@ +#[rustversion::not(nightly)] +#[ignore] +#[test] +fn test_backtrace() {} + +#[rustversion::nightly] +#[test] +fn test_backtrace() { + use anyhow::anyhow; + + let error = anyhow!("oh no!"); + let _ = error.backtrace(); +} diff --git a/src/rust/vendor/anyhow/tests/test_boxed.rs b/src/rust/vendor/anyhow/tests/test_boxed.rs new file mode 100644 index 000000000..38a568fb7 --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_boxed.rs @@ -0,0 +1,40 @@ +use anyhow::anyhow; +use std::error::Error as StdError; +use std::io; +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("outer")] +struct MyError { + source: io::Error, +} + +#[test] +fn test_boxed_str() { + let error = Box::::from("oh no!"); + let error = anyhow!(error); + assert_eq!("oh no!", error.to_string()); + assert_eq!( + "oh no!", + error + .downcast_ref::>() + .unwrap() + .to_string() + ); +} + +#[test] +fn test_boxed_thiserror() { + let error = MyError { + source: io::Error::new(io::ErrorKind::Other, "oh no!"), + }; + let error = anyhow!(error); + assert_eq!("oh no!", error.source().unwrap().to_string()); +} + +#[test] +fn test_boxed_anyhow() { + let error = anyhow!("oh no!").context("it failed"); + let error = anyhow!(error); + assert_eq!("oh no!", error.source().unwrap().to_string()); +} diff --git a/src/rust/vendor/anyhow/tests/test_chain.rs b/src/rust/vendor/anyhow/tests/test_chain.rs new file mode 100644 index 000000000..b1c5a3daa --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_chain.rs @@ -0,0 +1,45 @@ +use anyhow::{anyhow, Error}; + +fn error() -> Error { + anyhow!(0).context(1).context(2).context(3) +} + +#[test] +fn test_iter() { + let e = error(); + let mut chain = e.chain(); + assert_eq!("3", chain.next().unwrap().to_string()); + assert_eq!("2", chain.next().unwrap().to_string()); + assert_eq!("1", chain.next().unwrap().to_string()); + assert_eq!("0", chain.next().unwrap().to_string()); + assert!(chain.next().is_none()); + assert!(chain.next_back().is_none()); +} + +#[test] +fn test_rev() { + let e = error(); + let mut chain = e.chain().rev(); + assert_eq!("0", chain.next().unwrap().to_string()); + assert_eq!("1", chain.next().unwrap().to_string()); + assert_eq!("2", chain.next().unwrap().to_string()); + assert_eq!("3", chain.next().unwrap().to_string()); + assert!(chain.next().is_none()); + assert!(chain.next_back().is_none()); +} + +#[test] +fn test_len() { + let e = error(); + let mut chain = e.chain(); + assert_eq!(4, chain.len()); + assert_eq!("3", chain.next().unwrap().to_string()); + assert_eq!(3, chain.len()); + assert_eq!("0", chain.next_back().unwrap().to_string()); + assert_eq!(2, chain.len()); + assert_eq!("2", chain.next().unwrap().to_string()); + assert_eq!(1, chain.len()); + assert_eq!("1", chain.next_back().unwrap().to_string()); + assert_eq!(0, chain.len()); + assert!(chain.next().is_none()); +} diff --git a/src/rust/vendor/anyhow/tests/test_context.rs b/src/rust/vendor/anyhow/tests/test_context.rs new file mode 100644 index 000000000..44c1c7036 --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_context.rs @@ -0,0 +1,159 @@ +mod drop; + +use crate::drop::{DetectDrop, Flag}; +use anyhow::{Context, Error, Result}; +use std::fmt::{self, Display}; +use thiserror::Error; + +// https://github.com/dtolnay/anyhow/issues/18 +#[test] +fn test_inference() -> Result<()> { + let x = "1"; + let y: u32 = x.parse().context("...")?; + assert_eq!(y, 1); + Ok(()) +} + +macro_rules! context_type { + ($name:ident) => { + #[derive(Debug)] + struct $name { + message: &'static str, + drop: DetectDrop, + } + + impl Display for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.message) + } + } + }; +} + +context_type!(HighLevel); +context_type!(MidLevel); + +#[derive(Error, Debug)] +#[error("{message}")] +struct LowLevel { + message: &'static str, + drop: DetectDrop, +} + +struct Dropped { + low: Flag, + mid: Flag, + high: Flag, +} + +impl Dropped { + fn none(&self) -> bool { + !self.low.get() && !self.mid.get() && !self.high.get() + } + + fn all(&self) -> bool { + self.low.get() && self.mid.get() && self.high.get() + } +} + +fn make_chain() -> (Error, Dropped) { + let dropped = Dropped { + low: Flag::new(), + mid: Flag::new(), + high: Flag::new(), + }; + + let low = LowLevel { + message: "no such file or directory", + drop: DetectDrop::new(&dropped.low), + }; + + // impl Context for Result + let mid = Err::<(), LowLevel>(low) + .context(MidLevel { + message: "failed to load config", + drop: DetectDrop::new(&dropped.mid), + }) + .unwrap_err(); + + // impl Context for Result + let high = Err::<(), Error>(mid) + .context(HighLevel { + message: "failed to start server", + drop: DetectDrop::new(&dropped.high), + }) + .unwrap_err(); + + (high, dropped) +} + +#[test] +fn test_downcast_ref() { + let (err, dropped) = make_chain(); + + assert!(!err.is::()); + assert!(err.downcast_ref::().is_none()); + + assert!(err.is::()); + let high = err.downcast_ref::().unwrap(); + assert_eq!(high.to_string(), "failed to start server"); + + assert!(err.is::()); + let mid = err.downcast_ref::().unwrap(); + assert_eq!(mid.to_string(), "failed to load config"); + + assert!(err.is::()); + let low = err.downcast_ref::().unwrap(); + assert_eq!(low.to_string(), "no such file or directory"); + + assert!(dropped.none()); + drop(err); + assert!(dropped.all()); +} + +#[test] +fn test_downcast_high() { + let (err, dropped) = make_chain(); + + let err = err.downcast::().unwrap(); + assert!(!dropped.high.get()); + assert!(dropped.low.get() && dropped.mid.get()); + + drop(err); + assert!(dropped.all()); +} + +#[test] +fn test_downcast_mid() { + let (err, dropped) = make_chain(); + + let err = err.downcast::().unwrap(); + assert!(!dropped.mid.get()); + assert!(dropped.low.get() && dropped.high.get()); + + drop(err); + assert!(dropped.all()); +} + +#[test] +fn test_downcast_low() { + let (err, dropped) = make_chain(); + + let err = err.downcast::().unwrap(); + assert!(!dropped.low.get()); + assert!(dropped.mid.get() && dropped.high.get()); + + drop(err); + assert!(dropped.all()); +} + +#[test] +fn test_unsuccessful_downcast() { + let (err, dropped) = make_chain(); + + let err = err.downcast::().unwrap_err(); + assert!(dropped.none()); + + drop(err); + assert!(dropped.all()); +} diff --git a/src/rust/vendor/anyhow/tests/test_convert.rs b/src/rust/vendor/anyhow/tests/test_convert.rs new file mode 100644 index 000000000..72da020be --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_convert.rs @@ -0,0 +1,24 @@ +mod drop; + +use self::drop::{DetectDrop, Flag}; +use anyhow::{Error, Result}; +use std::error::Error as StdError; + +#[test] +fn test_convert() { + let has_dropped = Flag::new(); + let error = Error::new(DetectDrop::new(&has_dropped)); + let box_dyn = Box::::from(error); + assert_eq!("oh no!", box_dyn.to_string()); + drop(box_dyn); + assert!(has_dropped.get()); +} + +#[test] +fn test_question_mark() -> Result<(), Box> { + fn f() -> Result<()> { + Ok(()) + } + f()?; + Ok(()) +} diff --git a/src/rust/vendor/anyhow/tests/test_downcast.rs b/src/rust/vendor/anyhow/tests/test_downcast.rs new file mode 100644 index 000000000..c2c3e129f --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_downcast.rs @@ -0,0 +1,106 @@ +mod common; +mod drop; + +use self::common::*; +use self::drop::{DetectDrop, Flag}; +use anyhow::Error; +use std::error::Error as StdError; +use std::fmt::{self, Display}; +use std::io; + +#[test] +fn test_downcast() { + assert_eq!( + "oh no!", + bail_literal().unwrap_err().downcast::<&str>().unwrap(), + ); + assert_eq!( + "oh no!", + bail_fmt().unwrap_err().downcast::().unwrap(), + ); + assert_eq!( + "oh no!", + bail_error() + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + ); +} + +#[test] +fn test_downcast_ref() { + assert_eq!( + "oh no!", + *bail_literal().unwrap_err().downcast_ref::<&str>().unwrap(), + ); + assert_eq!( + "oh no!", + bail_fmt().unwrap_err().downcast_ref::().unwrap(), + ); + assert_eq!( + "oh no!", + bail_error() + .unwrap_err() + .downcast_ref::() + .unwrap() + .to_string(), + ); +} + +#[test] +fn test_downcast_mut() { + assert_eq!( + "oh no!", + *bail_literal().unwrap_err().downcast_mut::<&str>().unwrap(), + ); + assert_eq!( + "oh no!", + bail_fmt().unwrap_err().downcast_mut::().unwrap(), + ); + assert_eq!( + "oh no!", + bail_error() + .unwrap_err() + .downcast_mut::() + .unwrap() + .to_string(), + ); +} + +#[test] +fn test_drop() { + let has_dropped = Flag::new(); + let error = Error::new(DetectDrop::new(&has_dropped)); + drop(error.downcast::().unwrap()); + assert!(has_dropped.get()); +} + +#[test] +fn test_large_alignment() { + #[repr(align(64))] + #[derive(Debug)] + struct LargeAlignedError(&'static str); + + impl Display for LargeAlignedError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.0) + } + } + + impl StdError for LargeAlignedError {} + + let error = Error::new(LargeAlignedError("oh no!")); + assert_eq!( + "oh no!", + error.downcast_ref::().unwrap().0 + ); +} + +#[test] +fn test_unsuccessful_downcast() { + let mut error = bail_error().unwrap_err(); + assert!(error.downcast_ref::<&str>().is_none()); + assert!(error.downcast_mut::<&str>().is_none()); + assert!(error.downcast::<&str>().is_err()); +} diff --git a/src/rust/vendor/anyhow/tests/test_fmt.rs b/src/rust/vendor/anyhow/tests/test_fmt.rs new file mode 100644 index 000000000..cc4929197 --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_fmt.rs @@ -0,0 +1,94 @@ +use anyhow::{bail, Context, Result}; +use std::io; + +fn f() -> Result<()> { + bail!(io::Error::new(io::ErrorKind::PermissionDenied, "oh no!")); +} + +fn g() -> Result<()> { + f().context("f failed") +} + +fn h() -> Result<()> { + g().context("g failed") +} + +const EXPECTED_ALTDISPLAY_F: &str = "oh no!"; + +const EXPECTED_ALTDISPLAY_G: &str = "f failed: oh no!"; + +const EXPECTED_ALTDISPLAY_H: &str = "g failed: f failed: oh no!"; + +const EXPECTED_DEBUG_F: &str = "oh no!"; + +const EXPECTED_DEBUG_G: &str = "\ +f failed + +Caused by: + oh no!\ +"; + +const EXPECTED_DEBUG_H: &str = "\ +g failed + +Caused by: + 0: f failed + 1: oh no!\ +"; + +const EXPECTED_ALTDEBUG_F: &str = "\ +Custom { + kind: PermissionDenied, + error: \"oh no!\", +}\ +"; + +const EXPECTED_ALTDEBUG_G: &str = "\ +Error { + context: \"f failed\", + source: Custom { + kind: PermissionDenied, + error: \"oh no!\", + }, +}\ +"; + +const EXPECTED_ALTDEBUG_H: &str = "\ +Error { + context: \"g failed\", + source: Error { + context: \"f failed\", + source: Custom { + kind: PermissionDenied, + error: \"oh no!\", + }, + }, +}\ +"; + +#[test] +fn test_display() { + assert_eq!("g failed", h().unwrap_err().to_string()); +} + +#[test] +fn test_altdisplay() { + assert_eq!(EXPECTED_ALTDISPLAY_F, format!("{:#}", f().unwrap_err())); + assert_eq!(EXPECTED_ALTDISPLAY_G, format!("{:#}", g().unwrap_err())); + assert_eq!(EXPECTED_ALTDISPLAY_H, format!("{:#}", h().unwrap_err())); +} + +#[test] +#[cfg_attr(not(backtrace), ignore)] +fn test_debug() { + assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err())); + assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err())); + assert_eq!(EXPECTED_DEBUG_H, format!("{:?}", h().unwrap_err())); +} + +#[test] +fn test_altdebug() { + assert_eq!(EXPECTED_ALTDEBUG_F, format!("{:#?}", f().unwrap_err())); + assert_eq!(EXPECTED_ALTDEBUG_G, format!("{:#?}", g().unwrap_err())); + assert_eq!(EXPECTED_ALTDEBUG_H, format!("{:#?}", h().unwrap_err())); +} diff --git a/src/rust/vendor/anyhow/tests/test_macros.rs b/src/rust/vendor/anyhow/tests/test_macros.rs new file mode 100644 index 000000000..c6888b6b6 --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_macros.rs @@ -0,0 +1,33 @@ +mod common; + +use self::common::*; +use anyhow::ensure; + +#[test] +fn test_messages() { + assert_eq!("oh no!", bail_literal().unwrap_err().to_string()); + assert_eq!("oh no!", bail_fmt().unwrap_err().to_string()); + assert_eq!("oh no!", bail_error().unwrap_err().to_string()); +} + +#[test] +fn test_ensure() { + let f = || { + ensure!(1 + 1 == 2, "This is correct"); + Ok(()) + }; + assert!(f().is_ok()); + + let v = 1; + let f = || { + ensure!(v + v == 2, "This is correct, v: {}", v); + Ok(()) + }; + assert!(f().is_ok()); + + let f = || { + ensure!(v + v == 1, "This is not correct, v: {}", v); + Ok(()) + }; + assert!(f().is_err()); +} diff --git a/src/rust/vendor/anyhow/tests/test_repr.rs b/src/rust/vendor/anyhow/tests/test_repr.rs new file mode 100644 index 000000000..72f5002ae --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_repr.rs @@ -0,0 +1,29 @@ +mod drop; + +use self::drop::{DetectDrop, Flag}; +use anyhow::Error; +use std::marker::Unpin; +use std::mem; + +#[test] +fn test_error_size() { + assert_eq!(mem::size_of::(), mem::size_of::()); +} + +#[test] +fn test_null_pointer_optimization() { + assert_eq!(mem::size_of::>(), mem::size_of::()); +} + +#[test] +fn test_autotraits() { + fn assert() {} + assert::(); +} + +#[test] +fn test_drop() { + let has_dropped = Flag::new(); + drop(Error::new(DetectDrop::new(&has_dropped))); + assert!(has_dropped.get()); +} diff --git a/src/rust/vendor/anyhow/tests/test_source.rs b/src/rust/vendor/anyhow/tests/test_source.rs new file mode 100644 index 000000000..018267d31 --- /dev/null +++ b/src/rust/vendor/anyhow/tests/test_source.rs @@ -0,0 +1,62 @@ +use anyhow::anyhow; +use std::error::Error as StdError; +use std::fmt::{self, Display}; +use std::io; + +#[derive(Debug)] +enum TestError { + Io(io::Error), +} + +impl Display for TestError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + TestError::Io(e) => Display::fmt(e, formatter), + } + } +} + +impl StdError for TestError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + TestError::Io(io) => Some(io), + } + } +} + +#[test] +fn test_literal_source() { + let error = anyhow!("oh no!"); + assert!(error.source().is_none()); +} + +#[test] +fn test_variable_source() { + let msg = "oh no!"; + let error = anyhow!(msg); + assert!(error.source().is_none()); + + let msg = msg.to_owned(); + let error = anyhow!(msg); + assert!(error.source().is_none()); +} + +#[test] +fn test_fmt_source() { + let error = anyhow!("{} {}!", "oh", "no"); + assert!(error.source().is_none()); +} + +#[test] +fn test_io_source() { + let io = io::Error::new(io::ErrorKind::Other, "oh no!"); + let error = anyhow!(TestError::Io(io)); + assert_eq!("oh no!", error.source().unwrap().to_string()); +} + +#[test] +fn test_anyhow_from_anyhow() { + let error = anyhow!("oh no!").context("context"); + let error = anyhow!(error); + assert_eq!("oh no!", error.source().unwrap().to_string()); +} diff --git a/src/rust/vendor/anyhow/tests/ui/no-impl.rs b/src/rust/vendor/anyhow/tests/ui/no-impl.rs new file mode 100644 index 000000000..d2e89afc1 --- /dev/null +++ b/src/rust/vendor/anyhow/tests/ui/no-impl.rs @@ -0,0 +1,8 @@ +use anyhow::anyhow; + +#[derive(Debug)] +struct Error; + +fn main() { + let _ = anyhow!(Error); +} diff --git a/src/rust/vendor/anyhow/tests/ui/no-impl.stderr b/src/rust/vendor/anyhow/tests/ui/no-impl.stderr new file mode 100644 index 000000000..be957370d --- /dev/null +++ b/src/rust/vendor/anyhow/tests/ui/no-impl.stderr @@ -0,0 +1,21 @@ +error[E0599]: no method named `anyhow_kind` found for reference `&Error` in the current scope + --> $DIR/no-impl.rs:7:13 + | +4 | struct Error; + | ------------- + | | + | doesn't satisfy `Error: anyhow::kind::TraitKind` + | doesn't satisfy `Error: std::convert::Into` + | doesn't satisfy `Error: std::fmt::Display` +... +7 | let _ = anyhow!(Error); + | ^^^^^^^^^^^^^^ method not found in `&Error` + | + = note: the method `anyhow_kind` exists but the following trait bounds were not satisfied: + `Error: std::convert::Into` + which is required by `Error: anyhow::kind::TraitKind` + `Error: std::fmt::Display` + which is required by `&Error: anyhow::kind::AdhocKind` + `&Error: std::convert::Into` + which is required by `&Error: anyhow::kind::TraitKind` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/rust/vendor/bytes/.cargo-checksum.json b/src/rust/vendor/bytes/.cargo-checksum.json new file mode 100644 index 000000000..323e065e2 --- /dev/null +++ b/src/rust/vendor/bytes/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".github/workflows/ci.yml":"a9556900b0cb9d0cfb906c8a7ab6021334258eb4e27c9e17155343e02f847904","CHANGELOG.md":"2342dffcf846b00035ac57245aaf4fb6fad757afbdd0d7b63c2a61fa9caff2c5","Cargo.toml":"db6541aace6d5d5ed6d5f83ece5d83a3f546ff0d39446f2081a9bbae3244aee2","LICENSE":"45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42","README.md":"2c2f6f1a240ad375f9dbd8e7f023510b645d98e327ea0a42ba339c94fd9baaa9","benches/buf.rs":"0485f20344c972688c4114be67232664892816c1636c8e683bf59c90a9774483","benches/bytes.rs":"8e275cba0eb0b5513f60fec1f7b184be1ee95f22ed0cf50dfc1d1588d0302f15","benches/bytes_mut.rs":"29e730022afb581b19e2250a363a493072f1c8696ec9879a39d78f6913c7f65a","ci/test-stable.sh":"6e010f1a95b72fea7bebdd217fda78427f3eb07b1e753f79507c71d982b2d38a","ci/tsan":"5194270c4e37b1a72e890c98eb2a4aae5f5506fb26a67af3d2834360d2e3d3c2","ci/tsan.sh":"5bad99cb9457fc19426c0e36875d4c44b4e31d0c571f4cdc20febdb882e7a01e","src/buf/buf_impl.rs":"fe1bc64bb9aef5b57d83901268f89bf148490e71bebc340c7ecc40ff95bcfb70","src/buf/buf_mut.rs":"d226189d9db76c9023537dcca0687aa5dd25851a9052d19154de8ee9b25bdee3","src/buf/ext/chain.rs":"337f58e1a8da5b4768e55921ff394f4ba3a0c6d476448fd5bceab6f3c1db1b3e","src/buf/ext/limit.rs":"a705d7cf38f9a11a904d6ee5e7afea83e9abdf8f454bb8e16b407b0e055dc11a","src/buf/ext/mod.rs":"ba2fa392c61b7429530c71797114e3f09d9b6b750b6f77f57fde964d2b218bc4","src/buf/ext/reader.rs":"ee4733fa2c2d893c6df8151c2333a46171619e8a45ec9bae863edc8deb438ac5","src/buf/ext/take.rs":"e92be765539b8b0c1cb67a01b691319cccd35fc098f2bb59ced3bbbe41ee0257","src/buf/ext/writer.rs":"3c52df6e73d09935d37bed9a05689c1966952f980b85b40aaab05081ec7ef6d8","src/buf/iter.rs":"a0de69367fa61d0d1c6c2ff4b4d337de9c5f4213d0c86e083226cf409666d860","src/buf/mod.rs":"4f8e3b4c4b69b7d004306d458ad835801e53659b38ca08312d7217d82da4c64f","src/buf/vec_deque.rs":"5a4063961d10380c1ab3681f8b3f6201112766d9f57a63e2861dc9f2b134668d","src/bytes.rs":"321c3b850246a81b4396d76355e4d0c1909557a32c69c39e41a9c53bbba8845f","src/bytes_mut.rs":"4be8b98a0f224617222d681c7968e62712bea35a26203365ef1f73be18df29e3","src/fmt/debug.rs":"19ebe7e5516e40ab712995f3ec2e0ba78ddfa905cce117e6d01e8eb330f3970a","src/fmt/hex.rs":"13755ec6f1b79923e1f1a05c51b179a38c03c40bb8ed2db0210e8901812e61e7","src/fmt/mod.rs":"176da4e359da99b8e5cf16e480cb7b978f574876827f1b9bb9c08da4d74ac0f5","src/lib.rs":"d8d531c7ac07dbed62b3c2283a1fa008218c9d5a0f0b1be337b00f02b0e59821","src/loom.rs":"5dc97a5afce14875a66e44cbf0afa67e084c8b6b8c560bc14e7a70ef73aee96e","src/serde.rs":"3ecd7e828cd4c2b7db93c807cb1548fad209e674df493edf7cda69a7b04d405d","tests/test_buf.rs":"b514eb448ba3a8b7b93c7b721a92e89bd6cda4bb5031d2081cdfc18e0eff350c","tests/test_buf_mut.rs":"07423cd2081741d51d9434519a98b81b563c684f03460ca1254917dbea2d6be9","tests/test_bytes.rs":"377d4cc7158ea7e7b244bb0fd93d372226f2185dd7566d852398205795100c7c","tests/test_bytes_odd_alloc.rs":"87d51d4ab6ad98193b140ea8158f6631eba985a204c2ea94d34b3bb157791a16","tests/test_bytes_vec_alloc.rs":"2b686b6ab44f924e69d8270a4f256eb3626a3b4db8c1919b74bc422c10124899","tests/test_chain.rs":"5223737fa091a2bec47e3a96c6758f0f14b42b940ca40b6381ce7c88cf7e4287","tests/test_debug.rs":"5b425e056a32d0319d1857b54c88cf58952397bda6fee26b39c624d6c1444eee","tests/test_iter.rs":"70ca3660f527991be5c2dbc73ad7e69d931498b8b11aaa4d7f8109be9010420f","tests/test_reader.rs":"f3a902e3d7478e0367a4d1830498dc71acede02037fb9856e396d58f855cef33","tests/test_serde.rs":"f0a3dd89ba85ecfd61ba7d1db07788eb727455acff0064b8da7ba7d3780ab2a0","tests/test_take.rs":"998d16facf37fa0b2358e7aa42380279d4466d8dde2a3f8c1ae8a082bb37b180"},"package":null} \ No newline at end of file diff --git a/src/rust/vendor/bytes/.github/workflows/ci.yml b/src/rust/vendor/bytes/.github/workflows/ci.yml new file mode 100644 index 000000000..164ec1344 --- /dev/null +++ b/src/rust/vendor/bytes/.github/workflows/ci.yml @@ -0,0 +1,163 @@ +name: CI + +on: + pull_request: + branches: + - master + push: + branches: + - master + +env: + RUSTFLAGS: -Dwarnings + RUST_BACKTRACE: 1 + +defaults: + run: + shell: bash + +jobs: + # Check formatting + rustfmt: + name: rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update stable && rustup default stable + - name: Check formatting + run: cargo fmt --all -- --check + + # TODO + # # Apply clippy lints + # clippy: + # name: clippy + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v2 + # - name: Apply clippy lints + # run: cargo clippy --all-features + + # This represents the minimum Rust version supported by + # Bytes. Updating this should be done in a dedicated PR. + # + # Tests are not run as tests may require newer versions of + # rust. + minrust: + name: minrust + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update 1.39.0 && rustup default 1.39.0 + - name: Check + run: . ci/test-stable.sh check + + # Stable + stable: + name: stable + strategy: + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update stable && rustup default stable + - name: Test + run: . ci/test-stable.sh test + + # Nightly + nightly: + name: nightly + env: + # Pin nightly to avoid being impacted by breakage + RUST_VERSION: nightly-2019-09-25 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update $RUST_VERSION && rustup default $RUST_VERSION + - name: Test + run: . ci/test-stable.sh test + + # Run tests on some extra platforms + cross: + name: cross + strategy: + matrix: + target: + - i686-unknown-linux-gnu + - armv7-unknown-linux-gnueabihf + - powerpc-unknown-linux-gnu + - powerpc64-unknown-linux-gnu + - wasm32-unknown-unknown + runs-on: ubuntu-16.04 + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update stable && rustup default stable + - name: cross build --target ${{ matrix.target }} + run: | + cargo install cross + cross build --target ${{ matrix.target }} + if: matrix.target != 'wasm32-unknown-unknown' + # WASM support + - name: cargo build --target ${{ matrix.target }} + run: | + rustup target add ${{ matrix.target }} + cargo build --target ${{ matrix.target }} + if: matrix.target == 'wasm32-unknown-unknown' + + # Sanitizers + tsan: + name: tsan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update nightly && rustup default nightly + - name: TSAN / MSAN + run: . ci/tsan.sh + + # Loom + loom: + name: loom + env: + # Pin nightly to avoid being impacted by breakage + RUST_VERSION: nightly-2020-05-19 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update $RUST_VERSION && rustup default $RUST_VERSION + - name: Loom tests + run: RUSTFLAGS="--cfg loom -Dwarnings" cargo test --lib + + publish_docs: + name: Publish Documentation + needs: + - rustfmt + # - clippy + - stable + - nightly + - minrust + - cross + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Rust + run: rustup update stable && rustup default stable + - name: Build documentation + run: cargo doc --no-deps --all-features + - name: Publish documentation + run: | + cd target/doc + git init + git add . + git -c user.name='ci' -c user.email='ci' commit -m 'Deploy Bytes API documentation' + git push -f -q https://git:${{ secrets.github_token }}@github.com/${{ github.repository }} HEAD:gh-pages + if: github.event_name == 'push' && github.event.ref == 'refs/heads/master' && github.repository == 'tokio-rs/bytes' diff --git a/src/rust/vendor/bytes/CHANGELOG.md b/src/rust/vendor/bytes/CHANGELOG.md new file mode 100644 index 000000000..5e6a0325e --- /dev/null +++ b/src/rust/vendor/bytes/CHANGELOG.md @@ -0,0 +1,159 @@ +# 0.5.5 (June 18, 2020) + +### Added +- Allow using the `serde` feature in `no_std` environments (#385). + +### Fix +- Fix `BufMut::advance_mut` to panic if advanced passed the capacity (#354).. +- Fix `BytesMut::freeze` ignoring amount previously `advance`d (#352). + +# 0.5.4 (January 23, 2020) + +### Added +- Make `Bytes::new` a `const fn`. +- Add `From` for `Bytes`. + +### Fix +- Fix reversed arguments in `PartialOrd` for `Bytes`. +- Fix `Bytes::truncate` losing original capacity when repr is an unshared `Vec`. +- Fix `Bytes::from(Vec)` when allocator gave `Vec` a pointer with LSB set. +- Fix panic in `Bytes::slice_ref` if argument is an empty slice. + +# 0.5.3 (December 12, 2019) + +### Added +- `must_use` attributes to `split`, `split_off`, and `split_to` methods (#337). + +### Fix +- Potential freeing of a null pointer in `Bytes` when constructed with an empty `Vec` (#341, #342). +- Calling `Bytes::truncate` with a size large than the length will no longer clear the `Bytes` (#333). + +# 0.5.2 (November 27, 2019) + +### Added +- `Limit` methods `into_inner`, `get_ref`, `get_mut`, `limit`, and `set_limit` (#325). + +# 0.5.1 (November 25, 2019) + +### Fix +- Growth documentation for `BytesMut` (#321) + +# 0.5.0 (November 25, 2019) + +### Fix +- Potential overflow in `copy_to_slice` + +### Changed +- Increased minimum supported Rust version to 1.39. +- `Bytes` is now a "trait object", allowing for custom allocation strategies (#298) +- `BytesMut` implicitly grows internal storage. `remaining_mut()` returns + `usize::MAX` (#316). +- `BufMut::bytes_mut` returns `&mut [MaybeUninit]` to reflect the unknown + initialization state (#305). +- `Buf` / `BufMut` implementations for `&[u8]` and `&mut [u8]` + respectively (#261). +- Move `Buf` / `BufMut` "extra" functions to an extension trait (#306). +- `BufMutExt::limit` (#309). +- `Bytes::slice` takes a `RangeBounds` argument (#265). +- `Bytes::from_static` is now a `const fn` (#311). +- A multitude of smaller performance optimizations. + +### Added +- `no_std` support (#281). +- `get_*`, `put_*`, `get_*_le`, and `put_*le` accessors for handling byte order. +- `BorrowMut` implementation for `BytesMut` (#185). + +### Removed +- `IntoBuf` (#288). +- `Buf` implementation for `&str` (#301). +- `byteorder` dependency (#280). +- `iovec` dependency, use `std::IoSlice` instead (#263). +- optional `either` dependency (#315). +- optional `i128` feature -- now available on stable. (#276). + +# 0.4.12 (March 6, 2019) + +### Added +- Implement `FromIterator<&'a u8>` for `BytesMut`/`Bytes` (#244). +- Implement `Buf` for `VecDeque` (#249). + +# 0.4.11 (November 17, 2018) + +* Use raw pointers for potentially racy loads (#233). +* Implement `BufRead` for `buf::Reader` (#232). +* Documentation tweaks (#234). + +# 0.4.10 (September 4, 2018) + +* impl `Buf` and `BufMut` for `Either` (#225). +* Add `Bytes::slice_ref` (#208). + +# 0.4.9 (July 12, 2018) + +* Add 128 bit number support behind a feature flag (#209). +* Implement `IntoBuf` for `&mut [u8]` + +# 0.4.8 (May 25, 2018) + +* Fix panic in `BytesMut` `FromIterator` implementation. +* Bytes: Recycle space when reserving space in vec mode (#197). +* Bytes: Add resize fn (#203). + +# 0.4.7 (April 27, 2018) + +* Make `Buf` and `BufMut` usable as trait objects (#186). +* impl BorrowMut for BytesMut (#185). +* Improve accessor performance (#195). + +# 0.4.6 (Janary 8, 2018) + +* Implement FromIterator for Bytes/BytesMut (#148). +* Add `advance` fn to Bytes/BytesMut (#166). +* Add `unsplit` fn to `BytesMut` (#162, #173). +* Improvements to Bytes split fns (#92). + +# 0.4.5 (August 12, 2017) + +* Fix range bug in `Take::bytes` +* Misc performance improvements +* Add extra `PartialEq` implementations. +* Add `Bytes::with_capacity` +* Implement `AsMut[u8]` for `BytesMut` + +# 0.4.4 (May 26, 2017) + +* Add serde support behind feature flag +* Add `extend_from_slice` on `Bytes` and `BytesMut` +* Add `truncate` and `clear` on `Bytes` +* Misc additional std trait implementations +* Misc performance improvements + +# 0.4.3 (April 30, 2017) + +* Fix Vec::advance_mut bug +* Bump minimum Rust version to 1.15 +* Misc performance tweaks + +# 0.4.2 (April 5, 2017) + +* Misc performance tweaks +* Improved `Debug` implementation for `Bytes` +* Avoid some incorrect assert panics + +# 0.4.1 (March 15, 2017) + +* Expose `buf` module and have most types available from there vs. root. +* Implement `IntoBuf` for `T: Buf`. +* Add `FromBuf` and `Buf::collect`. +* Add iterator adapter for `Buf`. +* Add scatter/gather support to `Buf` and `BufMut`. +* Add `Buf::chain`. +* Reduce allocations on repeated calls to `BytesMut::reserve`. +* Implement `Debug` for more types. +* Remove `Source` in favor of `IntoBuf`. +* Implement `Extend` for `BytesMut`. + + +# 0.4.0 (February 24, 2017) + +* Initial release diff --git a/src/rust/vendor/bytes/Cargo.toml b/src/rust/vendor/bytes/Cargo.toml new file mode 100644 index 000000000..8524e7547 --- /dev/null +++ b/src/rust/vendor/bytes/Cargo.toml @@ -0,0 +1,28 @@ +[package] + +name = "bytes" +# When releasing to crates.io: +# - Update html_root_url. +# - Update CHANGELOG.md. +# - Update doc URL. +# - Create "v0.5.x" git tag. +version = "0.5.5" +license = "MIT" +authors = [ + "Carl Lerche ", + "Sean McArthur ", +] +description = "Types and traits for working with bytes" +documentation = "https://docs.rs/bytes" +repository = "https://github.com/tokio-rs/bytes" +readme = "README.md" +keywords = ["buffers", "zero-copy", "io"] +categories = ["network-programming", "data-structures"] +edition = "2018" + +[features] +default = ["std"] +std = [] + +[dependencies] +serde = { version = "1.0.60", optional = true, default-features = false, features = ["alloc"] } diff --git a/src/rust/vendor/bytes/LICENSE b/src/rust/vendor/bytes/LICENSE new file mode 100644 index 000000000..58fb29a12 --- /dev/null +++ b/src/rust/vendor/bytes/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2018 Carl Lerche + +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. diff --git a/src/rust/vendor/bytes/README.md b/src/rust/vendor/bytes/README.md new file mode 100644 index 000000000..73c43abc8 --- /dev/null +++ b/src/rust/vendor/bytes/README.md @@ -0,0 +1,47 @@ +# Bytes + +A utility library for working with bytes. + +[![Crates.io][crates-badge]][crates-url] +[![Build Status][ci-badge]][ci-url] + +[crates-badge]: https://img.shields.io/crates/v/bytes.svg +[crates-url]: https://crates.io/crates/bytes +[ci-badge]: https://github.com/tokio-rs/bytes/workflows/CI/badge.svg +[ci-url]: https://github.com/tokio-rs/bytes/actions + +[Documentation](https://docs.rs/bytes) + +## Usage + +To use `bytes`, first add this to your `Cargo.toml`: + +```toml +[dependencies] +bytes = "0.5" +``` + +Next, add this to your crate: + +```rust +use bytes::{Bytes, BytesMut, Buf, BufMut}; +``` + +## Serde support + +Serde support is optional and disabled by default. To enable use the feature `serde`. + +```toml +[dependencies] +bytes = { version = "0.5", features = ["serde"] } +``` + +## License + +This project is licensed under the [MIT license](LICENSE). + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `bytes` by you, shall be licensed as MIT, without any additional +terms or conditions. diff --git a/src/rust/vendor/bytes/benches/buf.rs b/src/rust/vendor/bytes/benches/buf.rs new file mode 100644 index 000000000..8f14aec20 --- /dev/null +++ b/src/rust/vendor/bytes/benches/buf.rs @@ -0,0 +1,187 @@ +#![feature(test)] +#![deny(warnings, rust_2018_idioms)] + +extern crate test; + +use bytes::Buf; +use test::Bencher; + +/// Dummy Buf implementation +struct TestBuf { + buf: &'static [u8], + readlens: &'static [usize], + init_pos: usize, + pos: usize, + readlen_pos: usize, + readlen: usize, +} +impl TestBuf { + fn new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBuf { + let mut buf = TestBuf { + buf, + readlens, + init_pos, + pos: 0, + readlen_pos: 0, + readlen: 0, + }; + buf.reset(); + buf + } + fn reset(&mut self) { + self.pos = self.init_pos; + self.readlen_pos = 0; + self.next_readlen(); + } + /// Compute the length of the next read : + /// - use the next value specified in readlens (capped by remaining) if any + /// - else the remaining + fn next_readlen(&mut self) { + self.readlen = self.buf.len() - self.pos; + if let Some(readlen) = self.readlens.get(self.readlen_pos) { + self.readlen = std::cmp::min(self.readlen, *readlen); + self.readlen_pos += 1; + } + } +} +impl Buf for TestBuf { + fn remaining(&self) -> usize { + return self.buf.len() - self.pos; + } + fn advance(&mut self, cnt: usize) { + self.pos += cnt; + assert!(self.pos <= self.buf.len()); + self.next_readlen(); + } + fn bytes(&self) -> &[u8] { + if self.readlen == 0 { + Default::default() + } else { + &self.buf[self.pos..self.pos + self.readlen] + } + } +} + +/// Dummy Buf implementation +/// version with methods forced to not be inlined (to simulate costly calls) +struct TestBufC { + inner: TestBuf, +} +impl TestBufC { + fn new(buf: &'static [u8], readlens: &'static [usize], init_pos: usize) -> TestBufC { + TestBufC { + inner: TestBuf::new(buf, readlens, init_pos), + } + } + fn reset(&mut self) { + self.inner.reset() + } +} +impl Buf for TestBufC { + #[inline(never)] + fn remaining(&self) -> usize { + self.inner.remaining() + } + #[inline(never)] + fn advance(&mut self, cnt: usize) { + self.inner.advance(cnt) + } + #[inline(never)] + fn bytes(&self) -> &[u8] { + self.inner.bytes() + } +} + +macro_rules! bench { + ($fname:ident, testbuf $testbuf:ident $readlens:expr, $method:ident $(,$arg:expr)*) => ( + #[bench] + fn $fname(b: &mut Bencher) { + let mut bufs = [ + $testbuf::new(&[1u8; 8+0], $readlens, 0), + $testbuf::new(&[1u8; 8+1], $readlens, 1), + $testbuf::new(&[1u8; 8+2], $readlens, 2), + $testbuf::new(&[1u8; 8+3], $readlens, 3), + $testbuf::new(&[1u8; 8+4], $readlens, 4), + $testbuf::new(&[1u8; 8+5], $readlens, 5), + $testbuf::new(&[1u8; 8+6], $readlens, 6), + $testbuf::new(&[1u8; 8+7], $readlens, 7), + ]; + b.iter(|| { + for i in 0..8 { + bufs[i].reset(); + let buf: &mut dyn Buf = &mut bufs[i]; // type erasure + test::black_box(buf.$method($($arg,)*)); + } + }) + } + ); + ($fname:ident, slice, $method:ident $(,$arg:expr)*) => ( + #[bench] + fn $fname(b: &mut Bencher) { + // buf must be long enough for one read of 8 bytes starting at pos 7 + let arr = [1u8; 8+7]; + b.iter(|| { + for i in 0..8 { + let mut buf = &arr[i..]; + let buf = &mut buf as &mut dyn Buf; // type erasure + test::black_box(buf.$method($($arg,)*)); + } + }) + } + ); + ($fname:ident, option) => ( + #[bench] + fn $fname(b: &mut Bencher) { + let data = [1u8; 1]; + b.iter(|| { + for _ in 0..8 { + let mut buf = Some(data); + let buf = &mut buf as &mut dyn Buf; // type erasure + test::black_box(buf.get_u8()); + } + }) + } + ); +} + +macro_rules! bench_group { + ($method:ident $(,$arg:expr)*) => ( + bench!(slice, slice, $method $(,$arg)*); + bench!(tbuf_1, testbuf TestBuf &[], $method $(,$arg)*); + bench!(tbuf_1_costly, testbuf TestBufC &[], $method $(,$arg)*); + bench!(tbuf_2, testbuf TestBuf &[1], $method $(,$arg)*); + bench!(tbuf_2_costly, testbuf TestBufC &[1], $method $(,$arg)*); + // bench!(tbuf_onebyone, testbuf TestBuf &[1,1,1,1,1,1,1,1], $method $(,$arg)*); + // bench!(tbuf_onebyone_costly, testbuf TestBufC &[1,1,1,1,1,1,1,1], $method $(,$arg)*); + ); +} + +mod get_u8 { + use super::*; + bench_group!(get_u8); + bench!(option, option); +} +mod get_u16 { + use super::*; + bench_group!(get_u16); +} +mod get_u32 { + use super::*; + bench_group!(get_u32); +} +mod get_u64 { + use super::*; + bench_group!(get_u64); +} +mod get_f32 { + use super::*; + bench_group!(get_f32); +} +mod get_f64 { + use super::*; + bench_group!(get_f64); +} +mod get_uint24 { + use super::*; + bench_group!(get_uint, 3); +} diff --git a/src/rust/vendor/bytes/benches/bytes.rs b/src/rust/vendor/bytes/benches/bytes.rs new file mode 100644 index 000000000..1741ba0a1 --- /dev/null +++ b/src/rust/vendor/bytes/benches/bytes.rs @@ -0,0 +1,119 @@ +#![feature(test)] +#![deny(warnings, rust_2018_idioms)] + +extern crate test; + +use bytes::Bytes; +use test::Bencher; + +#[bench] +fn deref_unique(b: &mut Bencher) { + let buf = Bytes::from(vec![0; 1024]); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn deref_shared(b: &mut Bencher) { + let buf = Bytes::from(vec![0; 1024]); + let _b2 = buf.clone(); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn deref_static(b: &mut Bencher) { + let buf = Bytes::from_static(b"hello world"); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn clone_static(b: &mut Bencher) { + let bytes = + Bytes::from_static("hello world 1234567890 and have a good byte 0987654321".as_bytes()); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&bytes.clone()); + } + }) +} + +#[bench] +fn clone_shared(b: &mut Bencher) { + let bytes = Bytes::from(b"hello world 1234567890 and have a good byte 0987654321".to_vec()); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&bytes.clone()); + } + }) +} + +#[bench] +fn clone_arc_vec(b: &mut Bencher) { + use std::sync::Arc; + let bytes = Arc::new(b"hello world 1234567890 and have a good byte 0987654321".to_vec()); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&bytes.clone()); + } + }) +} + +#[bench] +fn from_long_slice(b: &mut Bencher) { + let data = [0u8; 128]; + b.bytes = data.len() as u64; + b.iter(|| { + let buf = Bytes::copy_from_slice(&data[..]); + test::black_box(buf); + }) +} + +#[bench] +fn slice_empty(b: &mut Bencher) { + b.iter(|| { + let b = Bytes::from(vec![17; 1024]).clone(); + for i in 0..1000 { + test::black_box(b.slice(i % 100..i % 100)); + } + }) +} + +#[bench] +fn slice_short_from_arc(b: &mut Bencher) { + b.iter(|| { + // `clone` is to convert to ARC + let b = Bytes::from(vec![17; 1024]).clone(); + for i in 0..1000 { + test::black_box(b.slice(1..2 + i % 10)); + } + }) +} + +#[bench] +fn split_off_and_drop(b: &mut Bencher) { + b.iter(|| { + for _ in 0..1024 { + let v = vec![10; 200]; + let mut b = Bytes::from(v); + test::black_box(b.split_off(100)); + test::black_box(b); + } + }) +} diff --git a/src/rust/vendor/bytes/benches/bytes_mut.rs b/src/rust/vendor/bytes/benches/bytes_mut.rs new file mode 100644 index 000000000..8e0226c76 --- /dev/null +++ b/src/rust/vendor/bytes/benches/bytes_mut.rs @@ -0,0 +1,266 @@ +#![feature(test)] +#![deny(warnings, rust_2018_idioms)] + +extern crate test; + +use bytes::{BufMut, BytesMut}; +use test::Bencher; + +#[bench] +fn alloc_small(b: &mut Bencher) { + b.iter(|| { + for _ in 0..1024 { + test::black_box(BytesMut::with_capacity(12)); + } + }) +} + +#[bench] +fn alloc_mid(b: &mut Bencher) { + b.iter(|| { + test::black_box(BytesMut::with_capacity(128)); + }) +} + +#[bench] +fn alloc_big(b: &mut Bencher) { + b.iter(|| { + test::black_box(BytesMut::with_capacity(4096)); + }) +} + +#[bench] +fn deref_unique(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(4096); + buf.put(&[0u8; 1024][..]); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn deref_unique_unroll(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(4096); + buf.put(&[0u8; 1024][..]); + + b.iter(|| { + for _ in 0..128 { + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn deref_shared(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(4096); + buf.put(&[0u8; 1024][..]); + let _b2 = buf.split_off(1024); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn deref_two(b: &mut Bencher) { + let mut buf1 = BytesMut::with_capacity(8); + buf1.put(&[0u8; 8][..]); + + let mut buf2 = BytesMut::with_capacity(4096); + buf2.put(&[0u8; 1024][..]); + + b.iter(|| { + for _ in 0..512 { + test::black_box(&buf1[..]); + test::black_box(&buf2[..]); + } + }) +} + +#[bench] +fn clone_frozen(b: &mut Bencher) { + let bytes = BytesMut::from(&b"hello world 1234567890 and have a good byte 0987654321"[..]) + .split() + .freeze(); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&bytes.clone()); + } + }) +} + +#[bench] +fn alloc_write_split_to_mid(b: &mut Bencher) { + b.iter(|| { + let mut buf = BytesMut::with_capacity(128); + buf.put_slice(&[0u8; 64]); + test::black_box(buf.split_to(64)); + }) +} + +#[bench] +fn drain_write_drain(b: &mut Bencher) { + let data = [0u8; 128]; + + b.iter(|| { + let mut buf = BytesMut::with_capacity(1024); + let mut parts = Vec::with_capacity(8); + + for _ in 0..8 { + buf.put(&data[..]); + parts.push(buf.split_to(128)); + } + + test::black_box(parts); + }) +} + +#[bench] +fn fmt_write(b: &mut Bencher) { + use std::fmt::Write; + let mut buf = BytesMut::with_capacity(128); + let s = "foo bar baz quux lorem ipsum dolor et"; + + b.bytes = s.len() as u64; + b.iter(|| { + let _ = write!(buf, "{}", s); + test::black_box(&buf); + unsafe { + buf.set_len(0); + } + }) +} + +#[bench] +fn bytes_mut_extend(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(256); + let data = [33u8; 32]; + + b.bytes = data.len() as u64 * 4; + b.iter(|| { + for _ in 0..4 { + buf.extend(&data); + } + test::black_box(&buf); + unsafe { + buf.set_len(0); + } + }); +} + +// BufMut for BytesMut vs Vec + +#[bench] +fn put_slice_bytes_mut(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(256); + let data = [33u8; 32]; + + b.bytes = data.len() as u64 * 4; + b.iter(|| { + for _ in 0..4 { + buf.put_slice(&data); + } + test::black_box(&buf); + unsafe { + buf.set_len(0); + } + }); +} + +#[bench] +fn put_u8_bytes_mut(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(256); + let cnt = 128; + + b.bytes = cnt as u64; + b.iter(|| { + for _ in 0..cnt { + buf.put_u8(b'x'); + } + test::black_box(&buf); + unsafe { + buf.set_len(0); + } + }); +} + +#[bench] +fn put_slice_vec(b: &mut Bencher) { + let mut buf = Vec::::with_capacity(256); + let data = [33u8; 32]; + + b.bytes = data.len() as u64 * 4; + b.iter(|| { + for _ in 0..4 { + buf.put_slice(&data); + } + test::black_box(&buf); + unsafe { + buf.set_len(0); + } + }); +} + +#[bench] +fn put_u8_vec(b: &mut Bencher) { + let mut buf = Vec::::with_capacity(256); + let cnt = 128; + + b.bytes = cnt as u64; + b.iter(|| { + for _ in 0..cnt { + buf.put_u8(b'x'); + } + test::black_box(&buf); + unsafe { + buf.set_len(0); + } + }); +} + +#[bench] +fn put_slice_vec_extend(b: &mut Bencher) { + let mut buf = Vec::::with_capacity(256); + let data = [33u8; 32]; + + b.bytes = data.len() as u64 * 4; + b.iter(|| { + for _ in 0..4 { + buf.extend_from_slice(&data); + } + test::black_box(&buf); + unsafe { + buf.set_len(0); + } + }); +} + +#[bench] +fn put_u8_vec_push(b: &mut Bencher) { + let mut buf = Vec::::with_capacity(256); + let cnt = 128; + + b.bytes = cnt as u64; + b.iter(|| { + for _ in 0..cnt { + buf.push(b'x'); + } + test::black_box(&buf); + unsafe { + buf.set_len(0); + } + }); +} diff --git a/src/rust/vendor/bytes/ci/test-stable.sh b/src/rust/vendor/bytes/ci/test-stable.sh new file mode 100644 index 000000000..01a32f5a6 --- /dev/null +++ b/src/rust/vendor/bytes/ci/test-stable.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +set -ex + +cmd="${1:-test}" + +# Install cargo-hack for feature flag test +cargo install cargo-hack + +# Run with each feature +# * --each-feature includes both default/no-default features +# * --optional-deps is needed for serde feature +cargo hack "${cmd}" --each-feature --optional-deps +# Run with all features +cargo "${cmd}" --all-features + +cargo doc --no-deps --all-features + +if [[ "${RUST_VERSION}" == "nightly"* ]]; then + # Check benchmarks + cargo check --benches + + # Check minimal versions + cargo clean + cargo update -Zminimal-versions + cargo check --all-features +fi diff --git a/src/rust/vendor/bytes/ci/tsan b/src/rust/vendor/bytes/ci/tsan new file mode 100644 index 000000000..e53f9b893 --- /dev/null +++ b/src/rust/vendor/bytes/ci/tsan @@ -0,0 +1,24 @@ +# TSAN suppressions file for `bytes` + +# TSAN does not understand fences and `Arc::drop` is implemented using a fence. +# This causes many false positives. +race:Arc*drop +race:arc*Weak*drop + +# `std` mpsc is not used in any Bytes code base. This race is triggered by some +# rust runtime logic. +race:std*mpsc_queue + +# Some test runtime races. Allocation should be race free +race:alloc::alloc + +# Not sure why this is warning, but it is in the test harness and not the library. +race:TestEvent*clone +race:test::run_tests_console::*closure + +# Probably more fences in std. +race:__call_tls_dtors + +# This ignores a false positive caused by `thread::park()`/`thread::unpark()`. +# See: https://github.com/rust-lang/rust/pull/54806#issuecomment-436193353 +race:pthread_cond_destroy diff --git a/src/rust/vendor/bytes/ci/tsan.sh b/src/rust/vendor/bytes/ci/tsan.sh new file mode 100644 index 000000000..7e5b3be6d --- /dev/null +++ b/src/rust/vendor/bytes/ci/tsan.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -ex + +export RUST_TEST_THREADS=1 +export ASAN_OPTIONS="detect_odr_violation=0 detect_leaks=0" +export TSAN_OPTIONS="suppressions=$(pwd)/ci/tsan" + +# Run address sanitizer +RUSTFLAGS="-Z sanitizer=address" \ +cargo test --target x86_64-unknown-linux-gnu --test test_bytes --test test_buf --test test_buf_mut + +# Run thread sanitizer +RUSTFLAGS="-Z sanitizer=thread" \ +cargo test --target x86_64-unknown-linux-gnu --test test_bytes --test test_buf --test test_buf_mut diff --git a/src/rust/vendor/bytes/src/buf/buf_impl.rs b/src/rust/vendor/bytes/src/buf/buf_impl.rs new file mode 100644 index 000000000..5cd7c686e --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/buf_impl.rs @@ -0,0 +1,1007 @@ +use core::{cmp, mem, ptr}; + +#[cfg(feature = "std")] +use std::io::IoSlice; + +use alloc::boxed::Box; + +macro_rules! buf_get_impl { + ($this:ident, $typ:tt::$conv:tt) => {{ + const SIZE: usize = mem::size_of::<$typ>(); + // try to convert directly from the bytes + // this Option trick is to avoid keeping a borrow on self + // when advance() is called (mut borrow) and to call bytes() only once + let ret = $this + .bytes() + .get(..SIZE) + .map(|src| unsafe { $typ::$conv(*(src as *const _ as *const [_; SIZE])) }); + + if let Some(ret) = ret { + // if the direct conversion was possible, advance and return + $this.advance(SIZE); + return ret; + } else { + // if not we copy the bytes in a temp buffer then convert + let mut buf = [0; SIZE]; + $this.copy_to_slice(&mut buf); // (do the advance) + return $typ::$conv(buf); + } + }}; + (le => $this:ident, $typ:tt, $len_to_read:expr) => {{ + debug_assert!(mem::size_of::<$typ>() >= $len_to_read); + + // The same trick as above does not improve the best case speed. + // It seems to be linked to the way the method is optimised by the compiler + let mut buf = [0; (mem::size_of::<$typ>())]; + $this.copy_to_slice(&mut buf[..($len_to_read)]); + return $typ::from_le_bytes(buf); + }}; + (be => $this:ident, $typ:tt, $len_to_read:expr) => {{ + debug_assert!(mem::size_of::<$typ>() >= $len_to_read); + + let mut buf = [0; (mem::size_of::<$typ>())]; + $this.copy_to_slice(&mut buf[mem::size_of::<$typ>() - ($len_to_read)..]); + return $typ::from_be_bytes(buf); + }}; +} + +/// Read bytes from a buffer. +/// +/// A buffer stores bytes in memory such that read operations are infallible. +/// The underlying storage may or may not be in contiguous memory. A `Buf` value +/// is a cursor into the buffer. Reading from `Buf` advances the cursor +/// position. It can be thought of as an efficient `Iterator` for collections of +/// bytes. +/// +/// The simplest `Buf` is a `&[u8]`. +/// +/// ``` +/// use bytes::Buf; +/// +/// let mut buf = &b"hello world"[..]; +/// +/// assert_eq!(b'h', buf.get_u8()); +/// assert_eq!(b'e', buf.get_u8()); +/// assert_eq!(b'l', buf.get_u8()); +/// +/// let mut rest = [0; 8]; +/// buf.copy_to_slice(&mut rest); +/// +/// assert_eq!(&rest[..], &b"lo world"[..]); +/// ``` +pub trait Buf { + /// Returns the number of bytes between the current position and the end of + /// the buffer. + /// + /// This value is greater than or equal to the length of the slice returned + /// by `bytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"hello world"[..]; + /// + /// assert_eq!(buf.remaining(), 11); + /// + /// buf.get_u8(); + /// + /// assert_eq!(buf.remaining(), 10); + /// ``` + /// + /// # Implementer notes + /// + /// Implementations of `remaining` should ensure that the return value does + /// not change unless a call is made to `advance` or any other function that + /// is documented to change the `Buf`'s current position. + fn remaining(&self) -> usize; + + /// Returns a slice starting at the current position and of length between 0 + /// and `Buf::remaining()`. Note that this *can* return shorter slice (this allows + /// non-continuous internal representation). + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"hello world"[..]; + /// + /// assert_eq!(buf.bytes(), &b"hello world"[..]); + /// + /// buf.advance(6); + /// + /// assert_eq!(buf.bytes(), &b"world"[..]); + /// ``` + /// + /// # Implementer notes + /// + /// This function should never panic. Once the end of the buffer is reached, + /// i.e., `Buf::remaining` returns 0, calls to `bytes` should return an + /// empty slice. + fn bytes(&self) -> &[u8]; + + /// Fills `dst` with potentially multiple slices starting at `self`'s + /// current position. + /// + /// If the `Buf` is backed by disjoint slices of bytes, `bytes_vectored` enables + /// fetching more than one slice at once. `dst` is a slice of `IoSlice` + /// references, enabling the slice to be directly used with [`writev`] + /// without any further conversion. The sum of the lengths of all the + /// buffers in `dst` will be less than or equal to `Buf::remaining()`. + /// + /// The entries in `dst` will be overwritten, but the data **contained** by + /// the slices **will not** be modified. If `bytes_vectored` does not fill every + /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices + /// in `self. + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// # Implementer notes + /// + /// This function should never panic. Once the end of the buffer is reached, + /// i.e., `Buf::remaining` returns 0, calls to `bytes_vectored` must return 0 + /// without mutating `dst`. + /// + /// Implementations should also take care to properly handle being called + /// with `dst` being a zero length slice. + /// + /// [`writev`]: http://man7.org/linux/man-pages/man2/readv.2.html + #[cfg(feature = "std")] + fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize { + if dst.is_empty() { + return 0; + } + + if self.has_remaining() { + dst[0] = IoSlice::new(self.bytes()); + 1 + } else { + 0 + } + } + + /// Advance the internal cursor of the Buf + /// + /// The next call to `bytes` will return a slice starting `cnt` bytes + /// further into the underlying buffer. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"hello world"[..]; + /// + /// assert_eq!(buf.bytes(), &b"hello world"[..]); + /// + /// buf.advance(6); + /// + /// assert_eq!(buf.bytes(), &b"world"[..]); + /// ``` + /// + /// # Panics + /// + /// This function **may** panic if `cnt > self.remaining()`. + /// + /// # Implementer notes + /// + /// It is recommended for implementations of `advance` to panic if `cnt > + /// self.remaining()`. If the implementation does not panic, the call must + /// behave as if `cnt == self.remaining()`. + /// + /// A call with `cnt == 0` should never panic and be a no-op. + fn advance(&mut self, cnt: usize); + + /// Returns true if there are any more bytes to consume + /// + /// This is equivalent to `self.remaining() != 0`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"a"[..]; + /// + /// assert!(buf.has_remaining()); + /// + /// buf.get_u8(); + /// + /// assert!(!buf.has_remaining()); + /// ``` + fn has_remaining(&self) -> bool { + self.remaining() > 0 + } + + /// Copies bytes from `self` into `dst`. + /// + /// The cursor is advanced by the number of bytes copied. `self` must have + /// enough remaining bytes to fill `dst`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"hello world"[..]; + /// let mut dst = [0; 5]; + /// + /// buf.copy_to_slice(&mut dst); + /// assert_eq!(&b"hello"[..], &dst); + /// assert_eq!(6, buf.remaining()); + /// ``` + /// + /// # Panics + /// + /// This function panics if `self.remaining() < dst.len()` + fn copy_to_slice(&mut self, dst: &mut [u8]) { + let mut off = 0; + + assert!(self.remaining() >= dst.len()); + + while off < dst.len() { + let cnt; + + unsafe { + let src = self.bytes(); + cnt = cmp::min(src.len(), dst.len() - off); + + ptr::copy_nonoverlapping(src.as_ptr(), dst[off..].as_mut_ptr(), cnt); + + off += cnt; + } + + self.advance(cnt); + } + } + + /// Gets an unsigned 8 bit integer from `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x08 hello"[..]; + /// assert_eq!(8, buf.get_u8()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is no more remaining data in `self`. + fn get_u8(&mut self) -> u8 { + assert!(self.remaining() >= 1); + let ret = self.bytes()[0]; + self.advance(1); + ret + } + + /// Gets a signed 8 bit integer from `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x08 hello"[..]; + /// assert_eq!(8, buf.get_i8()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is no more remaining data in `self`. + fn get_i8(&mut self) -> i8 { + assert!(self.remaining() >= 1); + let ret = self.bytes()[0] as i8; + self.advance(1); + ret + } + + /// Gets an unsigned 16 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x08\x09 hello"[..]; + /// assert_eq!(0x0809, buf.get_u16()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u16(&mut self) -> u16 { + buf_get_impl!(self, u16::from_be_bytes); + } + + /// Gets an unsigned 16 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x09\x08 hello"[..]; + /// assert_eq!(0x0809, buf.get_u16_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u16_le(&mut self) -> u16 { + buf_get_impl!(self, u16::from_le_bytes); + } + + /// Gets a signed 16 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x08\x09 hello"[..]; + /// assert_eq!(0x0809, buf.get_i16()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i16(&mut self) -> i16 { + buf_get_impl!(self, i16::from_be_bytes); + } + + /// Gets a signed 16 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x09\x08 hello"[..]; + /// assert_eq!(0x0809, buf.get_i16_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i16_le(&mut self) -> i16 { + buf_get_impl!(self, i16::from_le_bytes); + } + + /// Gets an unsigned 32 bit integer from `self` in the big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x08\x09\xA0\xA1 hello"[..]; + /// assert_eq!(0x0809A0A1, buf.get_u32()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u32(&mut self) -> u32 { + buf_get_impl!(self, u32::from_be_bytes); + } + + /// Gets an unsigned 32 bit integer from `self` in the little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\xA1\xA0\x09\x08 hello"[..]; + /// assert_eq!(0x0809A0A1, buf.get_u32_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u32_le(&mut self) -> u32 { + buf_get_impl!(self, u32::from_le_bytes); + } + + /// Gets a signed 32 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x08\x09\xA0\xA1 hello"[..]; + /// assert_eq!(0x0809A0A1, buf.get_i32()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i32(&mut self) -> i32 { + buf_get_impl!(self, i32::from_be_bytes); + } + + /// Gets a signed 32 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\xA1\xA0\x09\x08 hello"[..]; + /// assert_eq!(0x0809A0A1, buf.get_i32_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i32_le(&mut self) -> i32 { + buf_get_impl!(self, i32::from_le_bytes); + } + + /// Gets an unsigned 64 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x01\x02\x03\x04\x05\x06\x07\x08 hello"[..]; + /// assert_eq!(0x0102030405060708, buf.get_u64()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u64(&mut self) -> u64 { + buf_get_impl!(self, u64::from_be_bytes); + } + + /// Gets an unsigned 64 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x08\x07\x06\x05\x04\x03\x02\x01 hello"[..]; + /// assert_eq!(0x0102030405060708, buf.get_u64_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u64_le(&mut self) -> u64 { + buf_get_impl!(self, u64::from_le_bytes); + } + + /// Gets a signed 64 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x01\x02\x03\x04\x05\x06\x07\x08 hello"[..]; + /// assert_eq!(0x0102030405060708, buf.get_i64()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i64(&mut self) -> i64 { + buf_get_impl!(self, i64::from_be_bytes); + } + + /// Gets a signed 64 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x08\x07\x06\x05\x04\x03\x02\x01 hello"[..]; + /// assert_eq!(0x0102030405060708, buf.get_i64_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i64_le(&mut self) -> i64 { + buf_get_impl!(self, i64::from_le_bytes); + } + + /// Gets an unsigned 128 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16 hello"[..]; + /// assert_eq!(0x01020304050607080910111213141516, buf.get_u128()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u128(&mut self) -> u128 { + buf_get_impl!(self, u128::from_be_bytes); + } + + /// Gets an unsigned 128 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01 hello"[..]; + /// assert_eq!(0x01020304050607080910111213141516, buf.get_u128_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u128_le(&mut self) -> u128 { + buf_get_impl!(self, u128::from_le_bytes); + } + + /// Gets a signed 128 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16 hello"[..]; + /// assert_eq!(0x01020304050607080910111213141516, buf.get_i128()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i128(&mut self) -> i128 { + buf_get_impl!(self, i128::from_be_bytes); + } + + /// Gets a signed 128 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01 hello"[..]; + /// assert_eq!(0x01020304050607080910111213141516, buf.get_i128_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i128_le(&mut self) -> i128 { + buf_get_impl!(self, i128::from_le_bytes); + } + + /// Gets an unsigned n-byte integer from `self` in big-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x01\x02\x03 hello"[..]; + /// assert_eq!(0x010203, buf.get_uint(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_uint(&mut self, nbytes: usize) -> u64 { + buf_get_impl!(be => self, u64, nbytes); + } + + /// Gets an unsigned n-byte integer from `self` in little-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x03\x02\x01 hello"[..]; + /// assert_eq!(0x010203, buf.get_uint_le(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_uint_le(&mut self, nbytes: usize) -> u64 { + buf_get_impl!(le => self, u64, nbytes); + } + + /// Gets a signed n-byte integer from `self` in big-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x01\x02\x03 hello"[..]; + /// assert_eq!(0x010203, buf.get_int(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_int(&mut self, nbytes: usize) -> i64 { + buf_get_impl!(be => self, i64, nbytes); + } + + /// Gets a signed n-byte integer from `self` in little-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x03\x02\x01 hello"[..]; + /// assert_eq!(0x010203, buf.get_int_le(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_int_le(&mut self, nbytes: usize) -> i64 { + buf_get_impl!(le => self, i64, nbytes); + } + + /// Gets an IEEE754 single-precision (4 bytes) floating point number from + /// `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x3F\x99\x99\x9A hello"[..]; + /// assert_eq!(1.2f32, buf.get_f32()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_f32(&mut self) -> f32 { + f32::from_bits(Self::get_u32(self)) + } + + /// Gets an IEEE754 single-precision (4 bytes) floating point number from + /// `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x9A\x99\x99\x3F hello"[..]; + /// assert_eq!(1.2f32, buf.get_f32_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_f32_le(&mut self) -> f32 { + f32::from_bits(Self::get_u32_le(self)) + } + + /// Gets an IEEE754 double-precision (8 bytes) floating point number from + /// `self` in big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x3F\xF3\x33\x33\x33\x33\x33\x33 hello"[..]; + /// assert_eq!(1.2f64, buf.get_f64()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_f64(&mut self) -> f64 { + f64::from_bits(Self::get_u64(self)) + } + + /// Gets an IEEE754 double-precision (8 bytes) floating point number from + /// `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let mut buf = &b"\x33\x33\x33\x33\x33\x33\xF3\x3F hello"[..]; + /// assert_eq!(1.2f64, buf.get_f64_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_f64_le(&mut self) -> f64 { + f64::from_bits(Self::get_u64_le(self)) + } + + /// Consumes remaining bytes inside self and returns new instance of `Bytes` + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// + /// let bytes = (&b"hello world"[..]).to_bytes(); + /// assert_eq!(&bytes[..], &b"hello world"[..]); + /// ``` + fn to_bytes(&mut self) -> crate::Bytes { + use super::BufMut; + let mut ret = crate::BytesMut::with_capacity(self.remaining()); + ret.put(self); + ret.freeze() + } +} + +macro_rules! deref_forward_buf { + () => { + fn remaining(&self) -> usize { + (**self).remaining() + } + + fn bytes(&self) -> &[u8] { + (**self).bytes() + } + + #[cfg(feature = "std")] + fn bytes_vectored<'b>(&'b self, dst: &mut [IoSlice<'b>]) -> usize { + (**self).bytes_vectored(dst) + } + + fn advance(&mut self, cnt: usize) { + (**self).advance(cnt) + } + + fn has_remaining(&self) -> bool { + (**self).has_remaining() + } + + fn copy_to_slice(&mut self, dst: &mut [u8]) { + (**self).copy_to_slice(dst) + } + + fn get_u8(&mut self) -> u8 { + (**self).get_u8() + } + + fn get_i8(&mut self) -> i8 { + (**self).get_i8() + } + + fn get_u16(&mut self) -> u16 { + (**self).get_u16() + } + + fn get_u16_le(&mut self) -> u16 { + (**self).get_u16_le() + } + + fn get_i16(&mut self) -> i16 { + (**self).get_i16() + } + + fn get_i16_le(&mut self) -> i16 { + (**self).get_i16_le() + } + + fn get_u32(&mut self) -> u32 { + (**self).get_u32() + } + + fn get_u32_le(&mut self) -> u32 { + (**self).get_u32_le() + } + + fn get_i32(&mut self) -> i32 { + (**self).get_i32() + } + + fn get_i32_le(&mut self) -> i32 { + (**self).get_i32_le() + } + + fn get_u64(&mut self) -> u64 { + (**self).get_u64() + } + + fn get_u64_le(&mut self) -> u64 { + (**self).get_u64_le() + } + + fn get_i64(&mut self) -> i64 { + (**self).get_i64() + } + + fn get_i64_le(&mut self) -> i64 { + (**self).get_i64_le() + } + + fn get_uint(&mut self, nbytes: usize) -> u64 { + (**self).get_uint(nbytes) + } + + fn get_uint_le(&mut self, nbytes: usize) -> u64 { + (**self).get_uint_le(nbytes) + } + + fn get_int(&mut self, nbytes: usize) -> i64 { + (**self).get_int(nbytes) + } + + fn get_int_le(&mut self, nbytes: usize) -> i64 { + (**self).get_int_le(nbytes) + } + + fn to_bytes(&mut self) -> crate::Bytes { + (**self).to_bytes() + } + }; +} + +impl Buf for &mut T { + deref_forward_buf!(); +} + +impl Buf for Box { + deref_forward_buf!(); +} + +impl Buf for &[u8] { + #[inline] + fn remaining(&self) -> usize { + self.len() + } + + #[inline] + fn bytes(&self) -> &[u8] { + self + } + + #[inline] + fn advance(&mut self, cnt: usize) { + *self = &self[cnt..]; + } +} + +impl Buf for Option<[u8; 1]> { + fn remaining(&self) -> usize { + if self.is_some() { + 1 + } else { + 0 + } + } + + fn bytes(&self) -> &[u8] { + self.as_ref() + .map(AsRef::as_ref) + .unwrap_or(Default::default()) + } + + fn advance(&mut self, cnt: usize) { + if cnt == 0 { + return; + } + + if self.is_none() { + panic!("overflow"); + } else { + assert_eq!(1, cnt); + *self = None; + } + } +} + +#[cfg(feature = "std")] +impl> Buf for std::io::Cursor { + fn remaining(&self) -> usize { + let len = self.get_ref().as_ref().len(); + let pos = self.position(); + + if pos >= len as u64 { + return 0; + } + + len - pos as usize + } + + fn bytes(&self) -> &[u8] { + let len = self.get_ref().as_ref().len(); + let pos = self.position(); + + if pos >= len as u64 { + return &[]; + } + + &self.get_ref().as_ref()[pos as usize..] + } + + fn advance(&mut self, cnt: usize) { + let pos = (self.position() as usize) + .checked_add(cnt) + .expect("overflow"); + + assert!(pos <= self.get_ref().as_ref().len()); + self.set_position(pos as u64); + } +} + +// The existence of this function makes the compiler catch if the Buf +// trait is "object-safe" or not. +fn _assert_trait_object(_b: &dyn Buf) {} diff --git a/src/rust/vendor/bytes/src/buf/buf_mut.rs b/src/rust/vendor/bytes/src/buf/buf_mut.rs new file mode 100644 index 000000000..628b240a3 --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/buf_mut.rs @@ -0,0 +1,1100 @@ +use core::{ + cmp, + mem::{self, MaybeUninit}, + ptr, usize, +}; + +#[cfg(feature = "std")] +use std::fmt; + +use alloc::{boxed::Box, vec::Vec}; + +/// A trait for values that provide sequential write access to bytes. +/// +/// Write bytes to a buffer +/// +/// A buffer stores bytes in memory such that write operations are infallible. +/// The underlying storage may or may not be in contiguous memory. A `BufMut` +/// value is a cursor into the buffer. Writing to `BufMut` advances the cursor +/// position. +/// +/// The simplest `BufMut` is a `Vec`. +/// +/// ``` +/// use bytes::BufMut; +/// +/// let mut buf = vec![]; +/// +/// buf.put(&b"hello world"[..]); +/// +/// assert_eq!(buf, b"hello world"); +/// ``` +pub trait BufMut { + /// Returns the number of bytes that can be written from the current + /// position until the end of the buffer is reached. + /// + /// This value is greater than or equal to the length of the slice returned + /// by `bytes_mut`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut dst = [0; 10]; + /// let mut buf = &mut dst[..]; + /// + /// let original_remaining = buf.remaining_mut(); + /// buf.put(&b"hello"[..]); + /// + /// assert_eq!(original_remaining - 5, buf.remaining_mut()); + /// ``` + /// + /// # Implementer notes + /// + /// Implementations of `remaining_mut` should ensure that the return value + /// does not change unless a call is made to `advance_mut` or any other + /// function that is documented to change the `BufMut`'s current position. + fn remaining_mut(&self) -> usize; + + /// Advance the internal cursor of the BufMut + /// + /// The next call to `bytes_mut` will return a slice starting `cnt` bytes + /// further into the underlying buffer. + /// + /// This function is unsafe because there is no guarantee that the bytes + /// being advanced past have been initialized. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = Vec::with_capacity(16); + /// + /// unsafe { + /// // MaybeUninit::as_mut_ptr + /// buf.bytes_mut()[0].as_mut_ptr().write(b'h'); + /// buf.bytes_mut()[1].as_mut_ptr().write(b'e'); + /// + /// buf.advance_mut(2); + /// + /// buf.bytes_mut()[0].as_mut_ptr().write(b'l'); + /// buf.bytes_mut()[1].as_mut_ptr().write(b'l'); + /// buf.bytes_mut()[2].as_mut_ptr().write(b'o'); + /// + /// buf.advance_mut(3); + /// } + /// + /// assert_eq!(5, buf.len()); + /// assert_eq!(buf, b"hello"); + /// ``` + /// + /// # Panics + /// + /// This function **may** panic if `cnt > self.remaining_mut()`. + /// + /// # Implementer notes + /// + /// It is recommended for implementations of `advance_mut` to panic if + /// `cnt > self.remaining_mut()`. If the implementation does not panic, + /// the call must behave as if `cnt == self.remaining_mut()`. + /// + /// A call with `cnt == 0` should never panic and be a no-op. + unsafe fn advance_mut(&mut self, cnt: usize); + + /// Returns true if there is space in `self` for more bytes. + /// + /// This is equivalent to `self.remaining_mut() != 0`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut dst = [0; 5]; + /// let mut buf = &mut dst[..]; + /// + /// assert!(buf.has_remaining_mut()); + /// + /// buf.put(&b"hello"[..]); + /// + /// assert!(!buf.has_remaining_mut()); + /// ``` + fn has_remaining_mut(&self) -> bool { + self.remaining_mut() > 0 + } + + /// Returns a mutable slice starting at the current BufMut position and of + /// length between 0 and `BufMut::remaining_mut()`. Note that this *can* be shorter than the + /// whole remainder of the buffer (this allows non-continuous implementation). + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// The returned byte slice may represent uninitialized memory. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = Vec::with_capacity(16); + /// + /// unsafe { + /// // MaybeUninit::as_mut_ptr + /// buf.bytes_mut()[0].as_mut_ptr().write(b'h'); + /// buf.bytes_mut()[1].as_mut_ptr().write(b'e'); + /// + /// buf.advance_mut(2); + /// + /// buf.bytes_mut()[0].as_mut_ptr().write(b'l'); + /// buf.bytes_mut()[1].as_mut_ptr().write(b'l'); + /// buf.bytes_mut()[2].as_mut_ptr().write(b'o'); + /// + /// buf.advance_mut(3); + /// } + /// + /// assert_eq!(5, buf.len()); + /// assert_eq!(buf, b"hello"); + /// ``` + /// + /// # Implementer notes + /// + /// This function should never panic. `bytes_mut` should return an empty + /// slice **if and only if** `remaining_mut` returns 0. In other words, + /// `bytes_mut` returning an empty slice implies that `remaining_mut` will + /// return 0 and `remaining_mut` returning 0 implies that `bytes_mut` will + /// return an empty slice. + fn bytes_mut(&mut self) -> &mut [MaybeUninit]; + + /// Fills `dst` with potentially multiple mutable slices starting at `self`'s + /// current position. + /// + /// If the `BufMut` is backed by disjoint slices of bytes, `bytes_vectored_mut` + /// enables fetching more than one slice at once. `dst` is a slice of + /// mutable `IoSliceMut` references, enabling the slice to be directly used with + /// [`readv`] without any further conversion. The sum of the lengths of all + /// the buffers in `dst` will be less than or equal to + /// `Buf::remaining_mut()`. + /// + /// The entries in `dst` will be overwritten, but the data **contained** by + /// the slices **will not** be modified. If `bytes_vectored_mut` does not fill every + /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices + /// in `self. + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// # Implementer notes + /// + /// This function should never panic. Once the end of the buffer is reached, + /// i.e., `BufMut::remaining_mut` returns 0, calls to `bytes_vectored_mut` must + /// return 0 without mutating `dst`. + /// + /// Implementations should also take care to properly handle being called + /// with `dst` being a zero length slice. + /// + /// [`readv`]: http://man7.org/linux/man-pages/man2/readv.2.html + #[cfg(feature = "std")] + fn bytes_vectored_mut<'a>(&'a mut self, dst: &mut [IoSliceMut<'a>]) -> usize { + if dst.is_empty() { + return 0; + } + + if self.has_remaining_mut() { + dst[0] = IoSliceMut::from(self.bytes_mut()); + 1 + } else { + 0 + } + } + + /// Transfer bytes into `self` from `src` and advance the cursor by the + /// number of bytes written. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// + /// buf.put_u8(b'h'); + /// buf.put(&b"ello"[..]); + /// buf.put(&b" world"[..]); + /// + /// assert_eq!(buf, b"hello world"); + /// ``` + /// + /// # Panics + /// + /// Panics if `self` does not have enough capacity to contain `src`. + fn put(&mut self, mut src: T) + where + Self: Sized, + { + assert!(self.remaining_mut() >= src.remaining()); + + while src.has_remaining() { + let l; + + unsafe { + let s = src.bytes(); + let d = self.bytes_mut(); + l = cmp::min(s.len(), d.len()); + + ptr::copy_nonoverlapping(s.as_ptr(), d.as_mut_ptr() as *mut u8, l); + } + + src.advance(l); + unsafe { + self.advance_mut(l); + } + } + } + + /// Transfer bytes into `self` from `src` and advance the cursor by the + /// number of bytes written. + /// + /// `self` must have enough remaining capacity to contain all of `src`. + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut dst = [0; 6]; + /// + /// { + /// let mut buf = &mut dst[..]; + /// buf.put_slice(b"hello"); + /// + /// assert_eq!(1, buf.remaining_mut()); + /// } + /// + /// assert_eq!(b"hello\0", &dst); + /// ``` + fn put_slice(&mut self, src: &[u8]) { + let mut off = 0; + + assert!( + self.remaining_mut() >= src.len(), + "buffer overflow; remaining = {}; src = {}", + self.remaining_mut(), + src.len() + ); + + while off < src.len() { + let cnt; + + unsafe { + let dst = self.bytes_mut(); + cnt = cmp::min(dst.len(), src.len() - off); + + ptr::copy_nonoverlapping(src[off..].as_ptr(), dst.as_mut_ptr() as *mut u8, cnt); + + off += cnt; + } + + unsafe { + self.advance_mut(cnt); + } + } + } + + /// Writes an unsigned 8 bit integer to `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u8(0x01); + /// assert_eq!(buf, b"\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u8(&mut self, n: u8) { + let src = [n]; + self.put_slice(&src); + } + + /// Writes a signed 8 bit integer to `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i8(0x01); + /// assert_eq!(buf, b"\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i8(&mut self, n: i8) { + let src = [n as u8]; + self.put_slice(&src) + } + + /// Writes an unsigned 16 bit integer to `self` in big-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u16(0x0809); + /// assert_eq!(buf, b"\x08\x09"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u16(&mut self, n: u16) { + self.put_slice(&n.to_be_bytes()) + } + + /// Writes an unsigned 16 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u16_le(0x0809); + /// assert_eq!(buf, b"\x09\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u16_le(&mut self, n: u16) { + self.put_slice(&n.to_le_bytes()) + } + + /// Writes a signed 16 bit integer to `self` in big-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i16(0x0809); + /// assert_eq!(buf, b"\x08\x09"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i16(&mut self, n: i16) { + self.put_slice(&n.to_be_bytes()) + } + + /// Writes a signed 16 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i16_le(0x0809); + /// assert_eq!(buf, b"\x09\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i16_le(&mut self, n: i16) { + self.put_slice(&n.to_le_bytes()) + } + + /// Writes an unsigned 32 bit integer to `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u32(0x0809A0A1); + /// assert_eq!(buf, b"\x08\x09\xA0\xA1"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u32(&mut self, n: u32) { + self.put_slice(&n.to_be_bytes()) + } + + /// Writes an unsigned 32 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u32_le(0x0809A0A1); + /// assert_eq!(buf, b"\xA1\xA0\x09\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u32_le(&mut self, n: u32) { + self.put_slice(&n.to_le_bytes()) + } + + /// Writes a signed 32 bit integer to `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i32(0x0809A0A1); + /// assert_eq!(buf, b"\x08\x09\xA0\xA1"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i32(&mut self, n: i32) { + self.put_slice(&n.to_be_bytes()) + } + + /// Writes a signed 32 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i32_le(0x0809A0A1); + /// assert_eq!(buf, b"\xA1\xA0\x09\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i32_le(&mut self, n: i32) { + self.put_slice(&n.to_le_bytes()) + } + + /// Writes an unsigned 64 bit integer to `self` in the big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u64(0x0102030405060708); + /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u64(&mut self, n: u64) { + self.put_slice(&n.to_be_bytes()) + } + + /// Writes an unsigned 64 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u64_le(0x0102030405060708); + /// assert_eq!(buf, b"\x08\x07\x06\x05\x04\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u64_le(&mut self, n: u64) { + self.put_slice(&n.to_le_bytes()) + } + + /// Writes a signed 64 bit integer to `self` in the big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i64(0x0102030405060708); + /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i64(&mut self, n: i64) { + self.put_slice(&n.to_be_bytes()) + } + + /// Writes a signed 64 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i64_le(0x0102030405060708); + /// assert_eq!(buf, b"\x08\x07\x06\x05\x04\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i64_le(&mut self, n: i64) { + self.put_slice(&n.to_le_bytes()) + } + + /// Writes an unsigned 128 bit integer to `self` in the big-endian byte order. + /// + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u128(0x01020304050607080910111213141516); + /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u128(&mut self, n: u128) { + self.put_slice(&n.to_be_bytes()) + } + + /// Writes an unsigned 128 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u128_le(0x01020304050607080910111213141516); + /// assert_eq!(buf, b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u128_le(&mut self, n: u128) { + self.put_slice(&n.to_le_bytes()) + } + + /// Writes a signed 128 bit integer to `self` in the big-endian byte order. + /// + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i128(0x01020304050607080910111213141516); + /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i128(&mut self, n: i128) { + self.put_slice(&n.to_be_bytes()) + } + + /// Writes a signed 128 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i128_le(0x01020304050607080910111213141516); + /// assert_eq!(buf, b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i128_le(&mut self, n: i128) { + self.put_slice(&n.to_le_bytes()) + } + + /// Writes an unsigned n-byte integer to `self` in big-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_uint(0x010203, 3); + /// assert_eq!(buf, b"\x01\x02\x03"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_uint(&mut self, n: u64, nbytes: usize) { + self.put_slice(&n.to_be_bytes()[mem::size_of_val(&n) - nbytes..]); + } + + /// Writes an unsigned n-byte integer to `self` in the little-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_uint_le(0x010203, 3); + /// assert_eq!(buf, b"\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_uint_le(&mut self, n: u64, nbytes: usize) { + self.put_slice(&n.to_le_bytes()[0..nbytes]); + } + + /// Writes a signed n-byte integer to `self` in big-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_int(0x010203, 3); + /// assert_eq!(buf, b"\x01\x02\x03"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_int(&mut self, n: i64, nbytes: usize) { + self.put_slice(&n.to_be_bytes()[mem::size_of_val(&n) - nbytes..]); + } + + /// Writes a signed n-byte integer to `self` in little-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_int_le(0x010203, 3); + /// assert_eq!(buf, b"\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_int_le(&mut self, n: i64, nbytes: usize) { + self.put_slice(&n.to_le_bytes()[0..nbytes]); + } + + /// Writes an IEEE754 single-precision (4 bytes) floating point number to + /// `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_f32(1.2f32); + /// assert_eq!(buf, b"\x3F\x99\x99\x9A"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_f32(&mut self, n: f32) { + self.put_u32(n.to_bits()); + } + + /// Writes an IEEE754 single-precision (4 bytes) floating point number to + /// `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_f32_le(1.2f32); + /// assert_eq!(buf, b"\x9A\x99\x99\x3F"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_f32_le(&mut self, n: f32) { + self.put_u32_le(n.to_bits()); + } + + /// Writes an IEEE754 double-precision (8 bytes) floating point number to + /// `self` in big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_f64(1.2f64); + /// assert_eq!(buf, b"\x3F\xF3\x33\x33\x33\x33\x33\x33"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_f64(&mut self, n: f64) { + self.put_u64(n.to_bits()); + } + + /// Writes an IEEE754 double-precision (8 bytes) floating point number to + /// `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_f64_le(1.2f64); + /// assert_eq!(buf, b"\x33\x33\x33\x33\x33\x33\xF3\x3F"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_f64_le(&mut self, n: f64) { + self.put_u64_le(n.to_bits()); + } +} + +macro_rules! deref_forward_bufmut { + () => { + fn remaining_mut(&self) -> usize { + (**self).remaining_mut() + } + + fn bytes_mut(&mut self) -> &mut [MaybeUninit] { + (**self).bytes_mut() + } + + #[cfg(feature = "std")] + fn bytes_vectored_mut<'b>(&'b mut self, dst: &mut [IoSliceMut<'b>]) -> usize { + (**self).bytes_vectored_mut(dst) + } + + unsafe fn advance_mut(&mut self, cnt: usize) { + (**self).advance_mut(cnt) + } + + fn put_slice(&mut self, src: &[u8]) { + (**self).put_slice(src) + } + + fn put_u8(&mut self, n: u8) { + (**self).put_u8(n) + } + + fn put_i8(&mut self, n: i8) { + (**self).put_i8(n) + } + + fn put_u16(&mut self, n: u16) { + (**self).put_u16(n) + } + + fn put_u16_le(&mut self, n: u16) { + (**self).put_u16_le(n) + } + + fn put_i16(&mut self, n: i16) { + (**self).put_i16(n) + } + + fn put_i16_le(&mut self, n: i16) { + (**self).put_i16_le(n) + } + + fn put_u32(&mut self, n: u32) { + (**self).put_u32(n) + } + + fn put_u32_le(&mut self, n: u32) { + (**self).put_u32_le(n) + } + + fn put_i32(&mut self, n: i32) { + (**self).put_i32(n) + } + + fn put_i32_le(&mut self, n: i32) { + (**self).put_i32_le(n) + } + + fn put_u64(&mut self, n: u64) { + (**self).put_u64(n) + } + + fn put_u64_le(&mut self, n: u64) { + (**self).put_u64_le(n) + } + + fn put_i64(&mut self, n: i64) { + (**self).put_i64(n) + } + + fn put_i64_le(&mut self, n: i64) { + (**self).put_i64_le(n) + } + }; +} + +impl BufMut for &mut T { + deref_forward_bufmut!(); +} + +impl BufMut for Box { + deref_forward_bufmut!(); +} + +impl BufMut for &mut [u8] { + #[inline] + fn remaining_mut(&self) -> usize { + self.len() + } + + #[inline] + fn bytes_mut(&mut self) -> &mut [MaybeUninit] { + // MaybeUninit is repr(transparent), so safe to transmute + unsafe { mem::transmute(&mut **self) } + } + + #[inline] + unsafe fn advance_mut(&mut self, cnt: usize) { + // Lifetime dance taken from `impl Write for &mut [u8]`. + let (_, b) = core::mem::replace(self, &mut []).split_at_mut(cnt); + *self = b; + } +} + +impl BufMut for Vec { + #[inline] + fn remaining_mut(&self) -> usize { + usize::MAX - self.len() + } + + #[inline] + unsafe fn advance_mut(&mut self, cnt: usize) { + let len = self.len(); + let remaining = self.capacity() - len; + + assert!( + cnt <= remaining, + "cannot advance past `remaining_mut`: {:?} <= {:?}", + cnt, + remaining + ); + + self.set_len(len + cnt); + } + + #[inline] + fn bytes_mut(&mut self) -> &mut [MaybeUninit] { + use core::slice; + + if self.capacity() == self.len() { + self.reserve(64); // Grow the vec + } + + let cap = self.capacity(); + let len = self.len(); + + let ptr = self.as_mut_ptr() as *mut MaybeUninit; + unsafe { &mut slice::from_raw_parts_mut(ptr, cap)[len..] } + } + + // Specialize these methods so they can skip checking `remaining_mut` + // and `advance_mut`. + + fn put(&mut self, mut src: T) + where + Self: Sized, + { + // In case the src isn't contiguous, reserve upfront + self.reserve(src.remaining()); + + while src.has_remaining() { + let l; + + // a block to contain the src.bytes() borrow + { + let s = src.bytes(); + l = s.len(); + self.extend_from_slice(s); + } + + src.advance(l); + } + } + + fn put_slice(&mut self, src: &[u8]) { + self.extend_from_slice(src); + } +} + +// The existence of this function makes the compiler catch if the BufMut +// trait is "object-safe" or not. +fn _assert_trait_object(_b: &dyn BufMut) {} + +// ===== impl IoSliceMut ===== + +/// A buffer type used for `readv`. +/// +/// This is a wrapper around an `std::io::IoSliceMut`, but does not expose +/// the inner bytes in a safe API, as they may point at uninitialized memory. +/// +/// This is `repr(transparent)` of the `std::io::IoSliceMut`, so it is valid to +/// transmute them. However, as the memory might be uninitialized, care must be +/// taken to not *read* the internal bytes, only *write* to them. +#[repr(transparent)] +#[cfg(feature = "std")] +pub struct IoSliceMut<'a>(std::io::IoSliceMut<'a>); + +#[cfg(feature = "std")] +impl fmt::Debug for IoSliceMut<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("IoSliceMut") + .field("len", &self.0.len()) + .finish() + } +} + +#[cfg(feature = "std")] +impl<'a> From<&'a mut [u8]> for IoSliceMut<'a> { + fn from(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut(std::io::IoSliceMut::new(buf)) + } +} + +#[cfg(feature = "std")] +impl<'a> From<&'a mut [MaybeUninit]> for IoSliceMut<'a> { + fn from(buf: &'a mut [MaybeUninit]) -> IoSliceMut<'a> { + IoSliceMut(std::io::IoSliceMut::new(unsafe { + // We don't look at the contents, and `std::io::IoSliceMut` + // doesn't either. + mem::transmute::<&'a mut [MaybeUninit], &'a mut [u8]>(buf) + })) + } +} diff --git a/src/rust/vendor/bytes/src/buf/ext/chain.rs b/src/rust/vendor/bytes/src/buf/ext/chain.rs new file mode 100644 index 000000000..e62e2f1b9 --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/ext/chain.rs @@ -0,0 +1,233 @@ +use crate::buf::IntoIter; +use crate::{Buf, BufMut}; + +use core::mem::MaybeUninit; + +#[cfg(feature = "std")] +use crate::buf::IoSliceMut; +#[cfg(feature = "std")] +use std::io::IoSlice; + +/// A `Chain` sequences two buffers. +/// +/// `Chain` is an adapter that links two underlying buffers and provides a +/// continuous view across both buffers. It is able to sequence either immutable +/// buffers ([`Buf`] values) or mutable buffers ([`BufMut`] values). +/// +/// This struct is generally created by calling [`Buf::chain`]. Please see that +/// function's documentation for more detail. +/// +/// # Examples +/// +/// ``` +/// use bytes::{Bytes, Buf, buf::BufExt}; +/// +/// let mut buf = (&b"hello "[..]) +/// .chain(&b"world"[..]); +/// +/// let full: Bytes = buf.to_bytes(); +/// assert_eq!(full[..], b"hello world"[..]); +/// ``` +/// +/// [`Buf::chain`]: trait.Buf.html#method.chain +/// [`Buf`]: trait.Buf.html +/// [`BufMut`]: trait.BufMut.html +#[derive(Debug)] +pub struct Chain { + a: T, + b: U, +} + +impl Chain { + /// Creates a new `Chain` sequencing the provided values. + pub fn new(a: T, b: U) -> Chain { + Chain { a, b } + } + + /// Gets a reference to the first underlying `Buf`. + /// + /// # Examples + /// + /// ``` + /// use bytes::buf::BufExt; + /// + /// let buf = (&b"hello"[..]) + /// .chain(&b"world"[..]); + /// + /// assert_eq!(buf.first_ref()[..], b"hello"[..]); + /// ``` + pub fn first_ref(&self) -> &T { + &self.a + } + + /// Gets a mutable reference to the first underlying `Buf`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, buf::BufExt}; + /// + /// let mut buf = (&b"hello"[..]) + /// .chain(&b"world"[..]); + /// + /// buf.first_mut().advance(1); + /// + /// let full = buf.to_bytes(); + /// assert_eq!(full, b"elloworld"[..]); + /// ``` + pub fn first_mut(&mut self) -> &mut T { + &mut self.a + } + + /// Gets a reference to the last underlying `Buf`. + /// + /// # Examples + /// + /// ``` + /// use bytes::buf::BufExt; + /// + /// let buf = (&b"hello"[..]) + /// .chain(&b"world"[..]); + /// + /// assert_eq!(buf.last_ref()[..], b"world"[..]); + /// ``` + pub fn last_ref(&self) -> &U { + &self.b + } + + /// Gets a mutable reference to the last underlying `Buf`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, buf::BufExt}; + /// + /// let mut buf = (&b"hello "[..]) + /// .chain(&b"world"[..]); + /// + /// buf.last_mut().advance(1); + /// + /// let full = buf.to_bytes(); + /// assert_eq!(full, b"hello orld"[..]); + /// ``` + pub fn last_mut(&mut self) -> &mut U { + &mut self.b + } + + /// Consumes this `Chain`, returning the underlying values. + /// + /// # Examples + /// + /// ``` + /// use bytes::buf::BufExt; + /// + /// let chain = (&b"hello"[..]) + /// .chain(&b"world"[..]); + /// + /// let (first, last) = chain.into_inner(); + /// assert_eq!(first[..], b"hello"[..]); + /// assert_eq!(last[..], b"world"[..]); + /// ``` + pub fn into_inner(self) -> (T, U) { + (self.a, self.b) + } +} + +impl Buf for Chain +where + T: Buf, + U: Buf, +{ + fn remaining(&self) -> usize { + self.a.remaining() + self.b.remaining() + } + + fn bytes(&self) -> &[u8] { + if self.a.has_remaining() { + self.a.bytes() + } else { + self.b.bytes() + } + } + + fn advance(&mut self, mut cnt: usize) { + let a_rem = self.a.remaining(); + + if a_rem != 0 { + if a_rem >= cnt { + self.a.advance(cnt); + return; + } + + // Consume what is left of a + self.a.advance(a_rem); + + cnt -= a_rem; + } + + self.b.advance(cnt); + } + + #[cfg(feature = "std")] + fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize { + let mut n = self.a.bytes_vectored(dst); + n += self.b.bytes_vectored(&mut dst[n..]); + n + } +} + +impl BufMut for Chain +where + T: BufMut, + U: BufMut, +{ + fn remaining_mut(&self) -> usize { + self.a.remaining_mut() + self.b.remaining_mut() + } + + fn bytes_mut(&mut self) -> &mut [MaybeUninit] { + if self.a.has_remaining_mut() { + self.a.bytes_mut() + } else { + self.b.bytes_mut() + } + } + + unsafe fn advance_mut(&mut self, mut cnt: usize) { + let a_rem = self.a.remaining_mut(); + + if a_rem != 0 { + if a_rem >= cnt { + self.a.advance_mut(cnt); + return; + } + + // Consume what is left of a + self.a.advance_mut(a_rem); + + cnt -= a_rem; + } + + self.b.advance_mut(cnt); + } + + #[cfg(feature = "std")] + fn bytes_vectored_mut<'a>(&'a mut self, dst: &mut [IoSliceMut<'a>]) -> usize { + let mut n = self.a.bytes_vectored_mut(dst); + n += self.b.bytes_vectored_mut(&mut dst[n..]); + n + } +} + +impl IntoIterator for Chain +where + T: Buf, + U: Buf, +{ + type Item = u8; + type IntoIter = IntoIter>; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self) + } +} diff --git a/src/rust/vendor/bytes/src/buf/ext/limit.rs b/src/rust/vendor/bytes/src/buf/ext/limit.rs new file mode 100644 index 000000000..a36eceeef --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/ext/limit.rs @@ -0,0 +1,74 @@ +use crate::BufMut; + +use core::{cmp, mem::MaybeUninit}; + +/// A `BufMut` adapter which limits the amount of bytes that can be written +/// to an underlying buffer. +#[derive(Debug)] +pub struct Limit { + inner: T, + limit: usize, +} + +pub(super) fn new(inner: T, limit: usize) -> Limit { + Limit { inner, limit } +} + +impl Limit { + /// Consumes this `Limit`, returning the underlying value. + pub fn into_inner(self) -> T { + self.inner + } + + /// Gets a reference to the underlying `BufMut`. + /// + /// It is inadvisable to directly write to the underlying `BufMut`. + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying `BufMut`. + /// + /// It is inadvisable to directly write to the underlying `BufMut`. + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } + + /// Returns the maximum number of bytes that can be written + /// + /// # Note + /// + /// If the inner `BufMut` has fewer bytes than indicated by this method then + /// that is the actual number of available bytes. + pub fn limit(&self) -> usize { + self.limit + } + + /// Sets the maximum number of bytes that can be written. + /// + /// # Note + /// + /// If the inner `BufMut` has fewer bytes than `lim` then that is the actual + /// number of available bytes. + pub fn set_limit(&mut self, lim: usize) { + self.limit = lim + } +} + +impl BufMut for Limit { + fn remaining_mut(&self) -> usize { + cmp::min(self.inner.remaining_mut(), self.limit) + } + + fn bytes_mut(&mut self) -> &mut [MaybeUninit] { + let bytes = self.inner.bytes_mut(); + let end = cmp::min(bytes.len(), self.limit); + &mut bytes[..end] + } + + unsafe fn advance_mut(&mut self, cnt: usize) { + assert!(cnt <= self.limit); + self.inner.advance_mut(cnt); + self.limit -= cnt; + } +} diff --git a/src/rust/vendor/bytes/src/buf/ext/mod.rs b/src/rust/vendor/bytes/src/buf/ext/mod.rs new file mode 100644 index 000000000..4a292676a --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/ext/mod.rs @@ -0,0 +1,186 @@ +//! Extra utilities for `Buf` and `BufMut` types. + +use super::{Buf, BufMut}; + +mod chain; +mod limit; +#[cfg(feature = "std")] +mod reader; +mod take; +#[cfg(feature = "std")] +mod writer; + +pub use self::chain::Chain; +pub use self::limit::Limit; +pub use self::take::Take; + +#[cfg(feature = "std")] +pub use self::{reader::Reader, writer::Writer}; + +/// Extra methods for implementations of `Buf`. +pub trait BufExt: Buf { + /// Creates an adaptor which will read at most `limit` bytes from `self`. + /// + /// This function returns a new instance of `Buf` which will read at most + /// `limit` bytes. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BufMut, buf::BufExt}; + /// + /// let mut buf = b"hello world"[..].take(5); + /// let mut dst = vec![]; + /// + /// dst.put(&mut buf); + /// assert_eq!(dst, b"hello"); + /// + /// let mut buf = buf.into_inner(); + /// dst.clear(); + /// dst.put(&mut buf); + /// assert_eq!(dst, b" world"); + /// ``` + fn take(self, limit: usize) -> Take + where + Self: Sized, + { + take::new(self, limit) + } + + /// Creates an adaptor which will chain this buffer with another. + /// + /// The returned `Buf` instance will first consume all bytes from `self`. + /// Afterwards the output is equivalent to the output of next. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, buf::BufExt}; + /// + /// let mut chain = b"hello "[..].chain(&b"world"[..]); + /// + /// let full = chain.to_bytes(); + /// assert_eq!(full.bytes(), b"hello world"); + /// ``` + fn chain(self, next: U) -> Chain + where + Self: Sized, + { + Chain::new(self, next) + } + + /// Creates an adaptor which implements the `Read` trait for `self`. + /// + /// This function returns a new value which implements `Read` by adapting + /// the `Read` trait functions to the `Buf` trait functions. Given that + /// `Buf` operations are infallible, none of the `Read` functions will + /// return with `Err`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, buf::BufExt}; + /// use std::io::Read; + /// + /// let buf = Bytes::from("hello world"); + /// + /// let mut reader = buf.reader(); + /// let mut dst = [0; 1024]; + /// + /// let num = reader.read(&mut dst).unwrap(); + /// + /// assert_eq!(11, num); + /// assert_eq!(&dst[..11], &b"hello world"[..]); + /// ``` + #[cfg(feature = "std")] + fn reader(self) -> Reader + where + Self: Sized, + { + reader::new(self) + } +} + +impl BufExt for B {} + +/// Extra methods for implementations of `BufMut`. +pub trait BufMutExt: BufMut { + /// Creates an adaptor which can write at most `limit` bytes to `self`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BufMut, buf::BufMutExt}; + /// + /// let arr = &mut [0u8; 128][..]; + /// assert_eq!(arr.remaining_mut(), 128); + /// + /// let dst = arr.limit(10); + /// assert_eq!(dst.remaining_mut(), 10); + /// ``` + fn limit(self, limit: usize) -> Limit + where + Self: Sized, + { + limit::new(self, limit) + } + + /// Creates an adaptor which implements the `Write` trait for `self`. + /// + /// This function returns a new value which implements `Write` by adapting + /// the `Write` trait functions to the `BufMut` trait functions. Given that + /// `BufMut` operations are infallible, none of the `Write` functions will + /// return with `Err`. + /// + /// # Examples + /// + /// ``` + /// use bytes::buf::BufMutExt; + /// use std::io::Write; + /// + /// let mut buf = vec![].writer(); + /// + /// let num = buf.write(&b"hello world"[..]).unwrap(); + /// assert_eq!(11, num); + /// + /// let buf = buf.into_inner(); + /// + /// assert_eq!(*buf, b"hello world"[..]); + /// ``` + #[cfg(feature = "std")] + fn writer(self) -> Writer + where + Self: Sized, + { + writer::new(self) + } + + /// Creates an adapter which will chain this buffer with another. + /// + /// The returned `BufMut` instance will first write to all bytes from + /// `self`. Afterwards, it will write to `next`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BufMut, buf::BufMutExt}; + /// + /// let mut a = [0u8; 5]; + /// let mut b = [0u8; 6]; + /// + /// let mut chain = (&mut a[..]).chain_mut(&mut b[..]); + /// + /// chain.put_slice(b"hello world"); + /// + /// assert_eq!(&a[..], b"hello"); + /// assert_eq!(&b[..], b" world"); + /// ``` + fn chain_mut(self, next: U) -> Chain + where + Self: Sized, + { + Chain::new(self, next) + } +} + +impl BufMutExt for B {} diff --git a/src/rust/vendor/bytes/src/buf/ext/reader.rs b/src/rust/vendor/bytes/src/buf/ext/reader.rs new file mode 100644 index 000000000..dde3548bf --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/ext/reader.rs @@ -0,0 +1,81 @@ +use crate::Buf; + +use std::{cmp, io}; + +/// A `Buf` adapter which implements `io::Read` for the inner value. +/// +/// This struct is generally created by calling `reader()` on `Buf`. See +/// documentation of [`reader()`](trait.Buf.html#method.reader) for more +/// details. +#[derive(Debug)] +pub struct Reader { + buf: B, +} + +pub fn new(buf: B) -> Reader { + Reader { buf } +} + +impl Reader { + /// Gets a reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::buf::BufExt; + /// + /// let buf = b"hello world".reader(); + /// + /// assert_eq!(b"hello world", buf.get_ref()); + /// ``` + pub fn get_ref(&self) -> &B { + &self.buf + } + + /// Gets a mutable reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + pub fn get_mut(&mut self) -> &mut B { + &mut self.buf + } + + /// Consumes this `Reader`, returning the underlying value. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, buf::BufExt}; + /// use std::io; + /// + /// let mut buf = b"hello world".reader(); + /// let mut dst = vec![]; + /// + /// io::copy(&mut buf, &mut dst).unwrap(); + /// + /// let buf = buf.into_inner(); + /// assert_eq!(0, buf.remaining()); + /// ``` + pub fn into_inner(self) -> B { + self.buf + } +} + +impl io::Read for Reader { + fn read(&mut self, dst: &mut [u8]) -> io::Result { + let len = cmp::min(self.buf.remaining(), dst.len()); + + Buf::copy_to_slice(&mut self.buf, &mut dst[0..len]); + Ok(len) + } +} + +impl io::BufRead for Reader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + Ok(self.buf.bytes()) + } + fn consume(&mut self, amt: usize) { + self.buf.advance(amt) + } +} diff --git a/src/rust/vendor/bytes/src/buf/ext/take.rs b/src/rust/vendor/bytes/src/buf/ext/take.rs new file mode 100644 index 000000000..1d84868bf --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/ext/take.rs @@ -0,0 +1,147 @@ +use crate::Buf; + +use core::cmp; + +/// A `Buf` adapter which limits the bytes read from an underlying buffer. +/// +/// This struct is generally created by calling `take()` on `Buf`. See +/// documentation of [`take()`](trait.BufExt.html#method.take) for more details. +#[derive(Debug)] +pub struct Take { + inner: T, + limit: usize, +} + +pub fn new(inner: T, limit: usize) -> Take { + Take { inner, limit } +} + +impl Take { + /// Consumes this `Take`, returning the underlying value. + /// + /// # Examples + /// + /// ```rust + /// use bytes::buf::{BufMut, BufExt}; + /// + /// let mut buf = b"hello world".take(2); + /// let mut dst = vec![]; + /// + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"he"[..]); + /// + /// let mut buf = buf.into_inner(); + /// + /// dst.clear(); + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"llo world"[..]); + /// ``` + pub fn into_inner(self) -> T { + self.inner + } + + /// Gets a reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, buf::BufExt}; + /// + /// let buf = b"hello world".take(2); + /// + /// assert_eq!(11, buf.get_ref().remaining()); + /// ``` + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, BufMut, buf::BufExt}; + /// + /// let mut buf = b"hello world".take(2); + /// let mut dst = vec![]; + /// + /// buf.get_mut().advance(2); + /// + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"ll"[..]); + /// ``` + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } + + /// Returns the maximum number of bytes that can be read. + /// + /// # Note + /// + /// If the inner `Buf` has fewer bytes than indicated by this method then + /// that is the actual number of available bytes. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, buf::BufExt}; + /// + /// let mut buf = b"hello world".take(2); + /// + /// assert_eq!(2, buf.limit()); + /// assert_eq!(b'h', buf.get_u8()); + /// assert_eq!(1, buf.limit()); + /// ``` + pub fn limit(&self) -> usize { + self.limit + } + + /// Sets the maximum number of bytes that can be read. + /// + /// # Note + /// + /// If the inner `Buf` has fewer bytes than `lim` then that is the actual + /// number of available bytes. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{BufMut, buf::BufExt}; + /// + /// let mut buf = b"hello world".take(2); + /// let mut dst = vec![]; + /// + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"he"[..]); + /// + /// dst.clear(); + /// + /// buf.set_limit(3); + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"llo"[..]); + /// ``` + pub fn set_limit(&mut self, lim: usize) { + self.limit = lim + } +} + +impl Buf for Take { + fn remaining(&self) -> usize { + cmp::min(self.inner.remaining(), self.limit) + } + + fn bytes(&self) -> &[u8] { + let bytes = self.inner.bytes(); + &bytes[..cmp::min(bytes.len(), self.limit)] + } + + fn advance(&mut self, cnt: usize) { + assert!(cnt <= self.limit); + self.inner.advance(cnt); + self.limit -= cnt; + } +} diff --git a/src/rust/vendor/bytes/src/buf/ext/writer.rs b/src/rust/vendor/bytes/src/buf/ext/writer.rs new file mode 100644 index 000000000..a14197c81 --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/ext/writer.rs @@ -0,0 +1,88 @@ +use crate::BufMut; + +use std::{cmp, io}; + +/// A `BufMut` adapter which implements `io::Write` for the inner value. +/// +/// This struct is generally created by calling `writer()` on `BufMut`. See +/// documentation of [`writer()`](trait.BufMut.html#method.writer) for more +/// details. +#[derive(Debug)] +pub struct Writer { + buf: B, +} + +pub fn new(buf: B) -> Writer { + Writer { buf } +} + +impl Writer { + /// Gets a reference to the underlying `BufMut`. + /// + /// It is inadvisable to directly write to the underlying `BufMut`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::buf::BufMutExt; + /// + /// let buf = Vec::with_capacity(1024).writer(); + /// + /// assert_eq!(1024, buf.get_ref().capacity()); + /// ``` + pub fn get_ref(&self) -> &B { + &self.buf + } + + /// Gets a mutable reference to the underlying `BufMut`. + /// + /// It is inadvisable to directly write to the underlying `BufMut`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::buf::BufMutExt; + /// + /// let mut buf = vec![].writer(); + /// + /// buf.get_mut().reserve(1024); + /// + /// assert_eq!(1024, buf.get_ref().capacity()); + /// ``` + pub fn get_mut(&mut self) -> &mut B { + &mut self.buf + } + + /// Consumes this `Writer`, returning the underlying value. + /// + /// # Examples + /// + /// ```rust + /// use bytes::buf::BufMutExt; + /// use std::io; + /// + /// let mut buf = vec![].writer(); + /// let mut src = &b"hello world"[..]; + /// + /// io::copy(&mut src, &mut buf).unwrap(); + /// + /// let buf = buf.into_inner(); + /// assert_eq!(*buf, b"hello world"[..]); + /// ``` + pub fn into_inner(self) -> B { + self.buf + } +} + +impl io::Write for Writer { + fn write(&mut self, src: &[u8]) -> io::Result { + let n = cmp::min(self.buf.remaining_mut(), src.len()); + + self.buf.put(&src[0..n]); + Ok(n) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} diff --git a/src/rust/vendor/bytes/src/buf/iter.rs b/src/rust/vendor/bytes/src/buf/iter.rs new file mode 100644 index 000000000..0f9bdc04f --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/iter.rs @@ -0,0 +1,133 @@ +use crate::Buf; + +/// Iterator over the bytes contained by the buffer. +/// +/// This struct is created by the [`iter`] method on [`Buf`]. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bytes::Bytes; +/// +/// let buf = Bytes::from(&b"abc"[..]); +/// let mut iter = buf.into_iter(); +/// +/// assert_eq!(iter.next(), Some(b'a')); +/// assert_eq!(iter.next(), Some(b'b')); +/// assert_eq!(iter.next(), Some(b'c')); +/// assert_eq!(iter.next(), None); +/// ``` +/// +/// [`iter`]: trait.Buf.html#method.iter +/// [`Buf`]: trait.Buf.html +#[derive(Debug)] +pub struct IntoIter { + inner: T, +} + +impl IntoIter { + /// Creates an iterator over the bytes contained by the buffer. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// use bytes::buf::IntoIter; + /// + /// let buf = Bytes::from_static(b"abc"); + /// let mut iter = IntoIter::new(buf); + /// + /// assert_eq!(iter.next(), Some(b'a')); + /// assert_eq!(iter.next(), Some(b'b')); + /// assert_eq!(iter.next(), Some(b'c')); + /// assert_eq!(iter.next(), None); + /// ``` + pub fn new(inner: T) -> IntoIter { + IntoIter { inner } + } + + /// Consumes this `IntoIter`, returning the underlying value. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, Bytes}; + /// + /// let buf = Bytes::from(&b"abc"[..]); + /// let mut iter = buf.into_iter(); + /// + /// assert_eq!(iter.next(), Some(b'a')); + /// + /// let buf = iter.into_inner(); + /// assert_eq!(2, buf.remaining()); + /// ``` + pub fn into_inner(self) -> T { + self.inner + } + + /// Gets a reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, Bytes}; + /// + /// let buf = Bytes::from(&b"abc"[..]); + /// let mut iter = buf.into_iter(); + /// + /// assert_eq!(iter.next(), Some(b'a')); + /// + /// assert_eq!(2, iter.get_ref().remaining()); + /// ``` + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, BytesMut}; + /// + /// let buf = BytesMut::from(&b"abc"[..]); + /// let mut iter = buf.into_iter(); + /// + /// assert_eq!(iter.next(), Some(b'a')); + /// + /// iter.get_mut().advance(1); + /// + /// assert_eq!(iter.next(), Some(b'c')); + /// ``` + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } +} + +impl Iterator for IntoIter { + type Item = u8; + + fn next(&mut self) -> Option { + if !self.inner.has_remaining() { + return None; + } + + let b = self.inner.bytes()[0]; + self.inner.advance(1); + + Some(b) + } + + fn size_hint(&self) -> (usize, Option) { + let rem = self.inner.remaining(); + (rem, Some(rem)) + } +} + +impl ExactSizeIterator for IntoIter {} diff --git a/src/rust/vendor/bytes/src/buf/mod.rs b/src/rust/vendor/bytes/src/buf/mod.rs new file mode 100644 index 000000000..1d7292c9e --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/mod.rs @@ -0,0 +1,30 @@ +//! Utilities for working with buffers. +//! +//! A buffer is any structure that contains a sequence of bytes. The bytes may +//! or may not be stored in contiguous memory. This module contains traits used +//! to abstract over buffers as well as utilities for working with buffer types. +//! +//! # `Buf`, `BufMut` +//! +//! These are the two foundational traits for abstractly working with buffers. +//! They can be thought as iterators for byte structures. They offer additional +//! performance over `Iterator` by providing an API optimized for byte slices. +//! +//! See [`Buf`] and [`BufMut`] for more details. +//! +//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure) +//! [`Buf`]: trait.Buf.html +//! [`BufMut`]: trait.BufMut.html + +mod buf_impl; +mod buf_mut; +pub mod ext; +mod iter; +mod vec_deque; + +pub use self::buf_impl::Buf; +pub use self::buf_mut::BufMut; +#[cfg(feature = "std")] +pub use self::buf_mut::IoSliceMut; +pub use self::ext::{BufExt, BufMutExt}; +pub use self::iter::IntoIter; diff --git a/src/rust/vendor/bytes/src/buf/vec_deque.rs b/src/rust/vendor/bytes/src/buf/vec_deque.rs new file mode 100644 index 000000000..195e6897f --- /dev/null +++ b/src/rust/vendor/bytes/src/buf/vec_deque.rs @@ -0,0 +1,22 @@ +use alloc::collections::VecDeque; + +use super::Buf; + +impl Buf for VecDeque { + fn remaining(&self) -> usize { + self.len() + } + + fn bytes(&self) -> &[u8] { + let (s1, s2) = self.as_slices(); + if s1.is_empty() { + s2 + } else { + s1 + } + } + + fn advance(&mut self, cnt: usize) { + self.drain(..cnt); + } +} diff --git a/src/rust/vendor/bytes/src/bytes.rs b/src/rust/vendor/bytes/src/bytes.rs new file mode 100644 index 000000000..08bc9b3f3 --- /dev/null +++ b/src/rust/vendor/bytes/src/bytes.rs @@ -0,0 +1,1108 @@ +use core::iter::FromIterator; +use core::ops::{Deref, RangeBounds}; +use core::{cmp, fmt, hash, mem, ptr, slice, usize}; + +use alloc::{borrow::Borrow, boxed::Box, string::String, vec::Vec}; + +use crate::buf::IntoIter; +#[allow(unused)] +use crate::loom::sync::atomic::AtomicMut; +use crate::loom::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; +use crate::Buf; + +/// A reference counted contiguous slice of memory. +/// +/// `Bytes` is an efficient container for storing and operating on contiguous +/// slices of memory. It is intended for use primarily in networking code, but +/// could have applications elsewhere as well. +/// +/// `Bytes` values facilitate zero-copy network programming by allowing multiple +/// `Bytes` objects to point to the same underlying memory. This is managed by +/// using a reference count to track when the memory is no longer needed and can +/// be freed. +/// +/// ``` +/// use bytes::Bytes; +/// +/// let mut mem = Bytes::from("Hello world"); +/// let a = mem.slice(0..5); +/// +/// assert_eq!(a, "Hello"); +/// +/// let b = mem.split_to(6); +/// +/// assert_eq!(mem, "world"); +/// assert_eq!(b, "Hello "); +/// ``` +/// +/// # Memory layout +/// +/// The `Bytes` struct itself is fairly small, limited to 4 `usize` fields used +/// to track information about which segment of the underlying memory the +/// `Bytes` handle has access to. +/// +/// `Bytes` keeps both a pointer to the shared `Arc` containing the full memory +/// slice and a pointer to the start of the region visible by the handle. +/// `Bytes` also tracks the length of its view into the memory. +/// +/// # Sharing +/// +/// The memory itself is reference counted, and multiple `Bytes` objects may +/// point to the same region. Each `Bytes` handle point to different sections within +/// the memory region, and `Bytes` handle may or may not have overlapping views +/// into the memory. +/// +/// +/// ```text +/// +/// Arc ptrs +---------+ +/// ________________________ / | Bytes 2 | +/// / +---------+ +/// / +-----------+ | | +/// |_________/ | Bytes 1 | | | +/// | +-----------+ | | +/// | | | ___/ data | tail +/// | data | tail |/ | +/// v v v v +/// +-----+---------------------------------+-----+ +/// | Arc | | | | | +/// +-----+---------------------------------+-----+ +/// ``` +pub struct Bytes { + ptr: *const u8, + len: usize, + // inlined "trait object" + data: AtomicPtr<()>, + vtable: &'static Vtable, +} + +pub(crate) struct Vtable { + /// fn(data, ptr, len) + pub clone: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> Bytes, + /// fn(data, ptr, len) + pub drop: unsafe fn(&mut AtomicPtr<()>, *const u8, usize), +} + +impl Bytes { + /// Creates a new empty `Bytes`. + /// + /// This will not allocate and the returned `Bytes` handle will be empty. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let b = Bytes::new(); + /// assert_eq!(&b[..], b""); + /// ``` + #[inline] + #[cfg(not(all(loom, test)))] + pub const fn new() -> Bytes { + // Make it a named const to work around + // "unsizing casts are not allowed in const fn" + const EMPTY: &[u8] = &[]; + Bytes::from_static(EMPTY) + } + + #[cfg(all(loom, test))] + pub fn new() -> Bytes { + const EMPTY: &[u8] = &[]; + Bytes::from_static(EMPTY) + } + + /// Creates a new `Bytes` from a static slice. + /// + /// The returned `Bytes` will point directly to the static slice. There is + /// no allocating or copying. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let b = Bytes::from_static(b"hello"); + /// assert_eq!(&b[..], b"hello"); + /// ``` + #[inline] + #[cfg(not(all(loom, test)))] + pub const fn from_static(bytes: &'static [u8]) -> Bytes { + Bytes { + ptr: bytes.as_ptr(), + len: bytes.len(), + data: AtomicPtr::new(ptr::null_mut()), + vtable: &STATIC_VTABLE, + } + } + + #[cfg(all(loom, test))] + pub fn from_static(bytes: &'static [u8]) -> Bytes { + Bytes { + ptr: bytes.as_ptr(), + len: bytes.len(), + data: AtomicPtr::new(ptr::null_mut()), + vtable: &STATIC_VTABLE, + } + } + + /// Returns the number of bytes contained in this `Bytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let b = Bytes::from(&b"hello"[..]); + /// assert_eq!(b.len(), 5); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.len + } + + /// Returns true if the `Bytes` has a length of 0. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let b = Bytes::new(); + /// assert!(b.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + ///Creates `Bytes` instance from slice, by copying it. + pub fn copy_from_slice(data: &[u8]) -> Self { + data.to_vec().into() + } + + /// Returns a slice of self for the provided range. + /// + /// This will increment the reference count for the underlying memory and + /// return a new `Bytes` handle set to the slice. + /// + /// This operation is `O(1)`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let a = Bytes::from(&b"hello world"[..]); + /// let b = a.slice(2..5); + /// + /// assert_eq!(&b[..], b"llo"); + /// ``` + /// + /// # Panics + /// + /// Requires that `begin <= end` and `end <= self.len()`, otherwise slicing + /// will panic. + pub fn slice(&self, range: impl RangeBounds) -> Bytes { + use core::ops::Bound; + + let len = self.len(); + + let begin = match range.start_bound() { + Bound::Included(&n) => n, + Bound::Excluded(&n) => n + 1, + Bound::Unbounded => 0, + }; + + let end = match range.end_bound() { + Bound::Included(&n) => n + 1, + Bound::Excluded(&n) => n, + Bound::Unbounded => len, + }; + + assert!( + begin <= end, + "range start must not be greater than end: {:?} <= {:?}", + begin, + end, + ); + assert!( + end <= len, + "range end out of bounds: {:?} <= {:?}", + end, + len, + ); + + if end == begin { + return Bytes::new(); + } + + let mut ret = self.clone(); + + ret.len = end - begin; + ret.ptr = unsafe { ret.ptr.offset(begin as isize) }; + + ret + } + + /// Returns a slice of self that is equivalent to the given `subset`. + /// + /// When processing a `Bytes` buffer with other tools, one often gets a + /// `&[u8]` which is in fact a slice of the `Bytes`, i.e. a subset of it. + /// This function turns that `&[u8]` into another `Bytes`, as if one had + /// called `self.slice()` with the offsets that correspond to `subset`. + /// + /// This operation is `O(1)`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let bytes = Bytes::from(&b"012345678"[..]); + /// let as_slice = bytes.as_ref(); + /// let subset = &as_slice[2..6]; + /// let subslice = bytes.slice_ref(&subset); + /// assert_eq!(&subslice[..], b"2345"); + /// ``` + /// + /// # Panics + /// + /// Requires that the given `sub` slice is in fact contained within the + /// `Bytes` buffer; otherwise this function will panic. + pub fn slice_ref(&self, subset: &[u8]) -> Bytes { + // Empty slice and empty Bytes may have their pointers reset + // so explicitly allow empty slice to be a subslice of any slice. + if subset.is_empty() { + return Bytes::new(); + } + + let bytes_p = self.as_ptr() as usize; + let bytes_len = self.len(); + + let sub_p = subset.as_ptr() as usize; + let sub_len = subset.len(); + + assert!( + sub_p >= bytes_p, + "subset pointer ({:p}) is smaller than self pointer ({:p})", + sub_p as *const u8, + bytes_p as *const u8, + ); + assert!( + sub_p + sub_len <= bytes_p + bytes_len, + "subset is out of bounds: self = ({:p}, {}), subset = ({:p}, {})", + bytes_p as *const u8, + bytes_len, + sub_p as *const u8, + sub_len, + ); + + let sub_offset = sub_p - bytes_p; + + self.slice(sub_offset..(sub_offset + sub_len)) + } + + /// Splits the bytes into two at the given index. + /// + /// Afterwards `self` contains elements `[0, at)`, and the returned `Bytes` + /// contains elements `[at, len)`. + /// + /// This is an `O(1)` operation that just increases the reference count and + /// sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut a = Bytes::from(&b"hello world"[..]); + /// let b = a.split_off(5); + /// + /// assert_eq!(&a[..], b"hello"); + /// assert_eq!(&b[..], b" world"); + /// ``` + /// + /// # Panics + /// + /// Panics if `at > len`. + #[must_use = "consider Bytes::truncate if you don't need the other half"] + pub fn split_off(&mut self, at: usize) -> Bytes { + assert!( + at <= self.len(), + "split_off out of bounds: {:?} <= {:?}", + at, + self.len(), + ); + + if at == self.len() { + return Bytes::new(); + } + + if at == 0 { + return mem::replace(self, Bytes::new()); + } + + let mut ret = self.clone(); + + self.len = at; + + unsafe { ret.inc_start(at) }; + + ret + } + + /// Splits the bytes into two at the given index. + /// + /// Afterwards `self` contains elements `[at, len)`, and the returned + /// `Bytes` contains elements `[0, at)`. + /// + /// This is an `O(1)` operation that just increases the reference count and + /// sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut a = Bytes::from(&b"hello world"[..]); + /// let b = a.split_to(5); + /// + /// assert_eq!(&a[..], b" world"); + /// assert_eq!(&b[..], b"hello"); + /// ``` + /// + /// # Panics + /// + /// Panics if `at > len`. + #[must_use = "consider Bytes::advance if you don't need the other half"] + pub fn split_to(&mut self, at: usize) -> Bytes { + assert!( + at <= self.len(), + "split_to out of bounds: {:?} <= {:?}", + at, + self.len(), + ); + + if at == self.len() { + return mem::replace(self, Bytes::new()); + } + + if at == 0 { + return Bytes::new(); + } + + let mut ret = self.clone(); + + unsafe { self.inc_start(at) }; + + ret.len = at; + ret + } + + /// Shortens the buffer, keeping the first `len` bytes and dropping the + /// rest. + /// + /// If `len` is greater than the buffer's current length, this has no + /// effect. + /// + /// The [`split_off`] method can emulate `truncate`, but this causes the + /// excess bytes to be returned instead of dropped. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut buf = Bytes::from(&b"hello world"[..]); + /// buf.truncate(5); + /// assert_eq!(buf, b"hello"[..]); + /// ``` + /// + /// [`split_off`]: #method.split_off + #[inline] + pub fn truncate(&mut self, len: usize) { + if len < self.len { + // The Vec "promotable" vtables do not store the capacity, + // so we cannot truncate while using this repr. We *have* to + // promote using `split_off` so the capacity can be stored. + if self.vtable as *const Vtable == &PROMOTABLE_EVEN_VTABLE + || self.vtable as *const Vtable == &PROMOTABLE_ODD_VTABLE + { + drop(self.split_off(len)); + } else { + self.len = len; + } + } + } + + /// Clears the buffer, removing all data. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut buf = Bytes::from(&b"hello world"[..]); + /// buf.clear(); + /// assert!(buf.is_empty()); + /// ``` + #[inline] + pub fn clear(&mut self) { + self.truncate(0); + } + + #[inline] + pub(crate) unsafe fn with_vtable( + ptr: *const u8, + len: usize, + data: AtomicPtr<()>, + vtable: &'static Vtable, + ) -> Bytes { + Bytes { + ptr, + len, + data, + vtable, + } + } + + // private + + #[inline] + fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.ptr, self.len) } + } + + #[inline] + unsafe fn inc_start(&mut self, by: usize) { + // should already be asserted, but debug assert for tests + debug_assert!(self.len >= by, "internal: inc_start out of bounds"); + self.len -= by; + self.ptr = self.ptr.offset(by as isize); + } +} + +// Vtable must enforce this behavior +unsafe impl Send for Bytes {} +unsafe impl Sync for Bytes {} + +impl Drop for Bytes { + #[inline] + fn drop(&mut self) { + unsafe { (self.vtable.drop)(&mut self.data, self.ptr, self.len) } + } +} + +impl Clone for Bytes { + #[inline] + fn clone(&self) -> Bytes { + unsafe { (self.vtable.clone)(&self.data, self.ptr, self.len) } + } +} + +impl Buf for Bytes { + #[inline] + fn remaining(&self) -> usize { + self.len() + } + + #[inline] + fn bytes(&self) -> &[u8] { + self.as_slice() + } + + #[inline] + fn advance(&mut self, cnt: usize) { + assert!( + cnt <= self.len(), + "cannot advance past `remaining`: {:?} <= {:?}", + cnt, + self.len(), + ); + + unsafe { + self.inc_start(cnt); + } + } + + fn to_bytes(&mut self) -> crate::Bytes { + core::mem::replace(self, Bytes::new()) + } +} + +impl Deref for Bytes { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.as_slice() + } +} + +impl AsRef<[u8]> for Bytes { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_slice() + } +} + +impl hash::Hash for Bytes { + fn hash(&self, state: &mut H) + where + H: hash::Hasher, + { + self.as_slice().hash(state); + } +} + +impl Borrow<[u8]> for Bytes { + fn borrow(&self) -> &[u8] { + self.as_slice() + } +} + +impl IntoIterator for Bytes { + type Item = u8; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self) + } +} + +impl<'a> IntoIterator for &'a Bytes { + type Item = &'a u8; + type IntoIter = core::slice::Iter<'a, u8>; + + fn into_iter(self) -> Self::IntoIter { + self.as_slice().into_iter() + } +} + +impl FromIterator for Bytes { + fn from_iter>(into_iter: T) -> Self { + Vec::from_iter(into_iter).into() + } +} + +// impl Eq + +impl PartialEq for Bytes { + fn eq(&self, other: &Bytes) -> bool { + self.as_slice() == other.as_slice() + } +} + +impl PartialOrd for Bytes { + fn partial_cmp(&self, other: &Bytes) -> Option { + self.as_slice().partial_cmp(other.as_slice()) + } +} + +impl Ord for Bytes { + fn cmp(&self, other: &Bytes) -> cmp::Ordering { + self.as_slice().cmp(other.as_slice()) + } +} + +impl Eq for Bytes {} + +impl PartialEq<[u8]> for Bytes { + fn eq(&self, other: &[u8]) -> bool { + self.as_slice() == other + } +} + +impl PartialOrd<[u8]> for Bytes { + fn partial_cmp(&self, other: &[u8]) -> Option { + self.as_slice().partial_cmp(other) + } +} + +impl PartialEq for [u8] { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for [u8] { + fn partial_cmp(&self, other: &Bytes) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self, other) + } +} + +impl PartialEq for Bytes { + fn eq(&self, other: &str) -> bool { + self.as_slice() == other.as_bytes() + } +} + +impl PartialOrd for Bytes { + fn partial_cmp(&self, other: &str) -> Option { + self.as_slice().partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for str { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for str { + fn partial_cmp(&self, other: &Bytes) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self.as_bytes(), other) + } +} + +impl PartialEq> for Bytes { + fn eq(&self, other: &Vec) -> bool { + *self == &other[..] + } +} + +impl PartialOrd> for Bytes { + fn partial_cmp(&self, other: &Vec) -> Option { + self.as_slice().partial_cmp(&other[..]) + } +} + +impl PartialEq for Vec { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for Vec { + fn partial_cmp(&self, other: &Bytes) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self, other) + } +} + +impl PartialEq for Bytes { + fn eq(&self, other: &String) -> bool { + *self == &other[..] + } +} + +impl PartialOrd for Bytes { + fn partial_cmp(&self, other: &String) -> Option { + self.as_slice().partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for String { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for String { + fn partial_cmp(&self, other: &Bytes) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self.as_bytes(), other) + } +} + +impl PartialEq for &[u8] { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for &[u8] { + fn partial_cmp(&self, other: &Bytes) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self, other) + } +} + +impl PartialEq for &str { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for &str { + fn partial_cmp(&self, other: &Bytes) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self.as_bytes(), other) + } +} + +impl<'a, T: ?Sized> PartialEq<&'a T> for Bytes +where + Bytes: PartialEq, +{ + fn eq(&self, other: &&'a T) -> bool { + *self == **other + } +} + +impl<'a, T: ?Sized> PartialOrd<&'a T> for Bytes +where + Bytes: PartialOrd, +{ + fn partial_cmp(&self, other: &&'a T) -> Option { + self.partial_cmp(&**other) + } +} + +// impl From + +impl Default for Bytes { + #[inline] + fn default() -> Bytes { + Bytes::new() + } +} + +impl From<&'static [u8]> for Bytes { + fn from(slice: &'static [u8]) -> Bytes { + Bytes::from_static(slice) + } +} + +impl From<&'static str> for Bytes { + fn from(slice: &'static str) -> Bytes { + Bytes::from_static(slice.as_bytes()) + } +} + +impl From> for Bytes { + fn from(vec: Vec) -> Bytes { + // into_boxed_slice doesn't return a heap allocation for empty vectors, + // so the pointer isn't aligned enough for the KIND_VEC stashing to + // work. + if vec.is_empty() { + return Bytes::new(); + } + + let slice = vec.into_boxed_slice(); + let len = slice.len(); + let ptr = slice.as_ptr(); + drop(Box::into_raw(slice)); + + if ptr as usize & 0x1 == 0 { + let data = ptr as usize | KIND_VEC; + Bytes { + ptr, + len, + data: AtomicPtr::new(data as *mut _), + vtable: &PROMOTABLE_EVEN_VTABLE, + } + } else { + Bytes { + ptr, + len, + data: AtomicPtr::new(ptr as *mut _), + vtable: &PROMOTABLE_ODD_VTABLE, + } + } + } +} + +impl From for Bytes { + fn from(s: String) -> Bytes { + Bytes::from(s.into_bytes()) + } +} + +// ===== impl Vtable ===== + +impl fmt::Debug for Vtable { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Vtable") + .field("clone", &(self.clone as *const ())) + .field("drop", &(self.drop as *const ())) + .finish() + } +} + +// ===== impl StaticVtable ===== + +const STATIC_VTABLE: Vtable = Vtable { + clone: static_clone, + drop: static_drop, +}; + +unsafe fn static_clone(_: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes { + let slice = slice::from_raw_parts(ptr, len); + Bytes::from_static(slice) +} + +unsafe fn static_drop(_: &mut AtomicPtr<()>, _: *const u8, _: usize) { + // nothing to drop for &'static [u8] +} + +// ===== impl PromotableVtable ===== + +static PROMOTABLE_EVEN_VTABLE: Vtable = Vtable { + clone: promotable_even_clone, + drop: promotable_even_drop, +}; + +static PROMOTABLE_ODD_VTABLE: Vtable = Vtable { + clone: promotable_odd_clone, + drop: promotable_odd_drop, +}; + +unsafe fn promotable_even_clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes { + let shared = data.load(Ordering::Acquire); + let kind = shared as usize & KIND_MASK; + + if kind == KIND_ARC { + shallow_clone_arc(shared as _, ptr, len) + } else { + debug_assert_eq!(kind, KIND_VEC); + let buf = (shared as usize & !KIND_MASK) as *mut u8; + shallow_clone_vec(data, shared, buf, ptr, len) + } +} + +unsafe fn promotable_even_drop(data: &mut AtomicPtr<()>, ptr: *const u8, len: usize) { + data.with_mut(|shared| { + let shared = *shared; + let kind = shared as usize & KIND_MASK; + + if kind == KIND_ARC { + release_shared(shared as *mut Shared); + } else { + debug_assert_eq!(kind, KIND_VEC); + let buf = (shared as usize & !KIND_MASK) as *mut u8; + drop(rebuild_boxed_slice(buf, ptr, len)); + } + }); +} + +unsafe fn promotable_odd_clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes { + let shared = data.load(Ordering::Acquire); + let kind = shared as usize & KIND_MASK; + + if kind == KIND_ARC { + shallow_clone_arc(shared as _, ptr, len) + } else { + debug_assert_eq!(kind, KIND_VEC); + shallow_clone_vec(data, shared, shared as *mut u8, ptr, len) + } +} + +unsafe fn promotable_odd_drop(data: &mut AtomicPtr<()>, ptr: *const u8, len: usize) { + data.with_mut(|shared| { + let shared = *shared; + let kind = shared as usize & KIND_MASK; + + if kind == KIND_ARC { + release_shared(shared as *mut Shared); + } else { + debug_assert_eq!(kind, KIND_VEC); + + drop(rebuild_boxed_slice(shared as *mut u8, ptr, len)); + } + }); +} + +unsafe fn rebuild_boxed_slice(buf: *mut u8, offset: *const u8, len: usize) -> Box<[u8]> { + let cap = (offset as usize - buf as usize) + len; + Box::from_raw(slice::from_raw_parts_mut(buf, cap)) +} + +// ===== impl SharedVtable ===== + +struct Shared { + // holds vec for drop, but otherwise doesnt access it + _vec: Vec, + ref_cnt: AtomicUsize, +} + +// Assert that the alignment of `Shared` is divisible by 2. +// This is a necessary invariant since we depend on allocating `Shared` a +// shared object to implicitly carry the `KIND_ARC` flag in its pointer. +// This flag is set when the LSB is 0. +const _: [(); 0 - mem::align_of::() % 2] = []; // Assert that the alignment of `Shared` is divisible by 2. + +static SHARED_VTABLE: Vtable = Vtable { + clone: shared_clone, + drop: shared_drop, +}; + +const KIND_ARC: usize = 0b0; +const KIND_VEC: usize = 0b1; +const KIND_MASK: usize = 0b1; + +unsafe fn shared_clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes { + let shared = data.load(Ordering::Acquire); + shallow_clone_arc(shared as _, ptr, len) +} + +unsafe fn shared_drop(data: &mut AtomicPtr<()>, _ptr: *const u8, _len: usize) { + data.with_mut(|shared| { + release_shared(*shared as *mut Shared); + }); +} + +unsafe fn shallow_clone_arc(shared: *mut Shared, ptr: *const u8, len: usize) -> Bytes { + let old_size = (*shared).ref_cnt.fetch_add(1, Ordering::Relaxed); + + if old_size > usize::MAX >> 1 { + crate::abort(); + } + + Bytes { + ptr, + len, + data: AtomicPtr::new(shared as _), + vtable: &SHARED_VTABLE, + } +} + +#[cold] +unsafe fn shallow_clone_vec( + atom: &AtomicPtr<()>, + ptr: *const (), + buf: *mut u8, + offset: *const u8, + len: usize, +) -> Bytes { + // If the buffer is still tracked in a `Vec`. It is time to + // promote the vec to an `Arc`. This could potentially be called + // concurrently, so some care must be taken. + + // First, allocate a new `Shared` instance containing the + // `Vec` fields. It's important to note that `ptr`, `len`, + // and `cap` cannot be mutated without having `&mut self`. + // This means that these fields will not be concurrently + // updated and since the buffer hasn't been promoted to an + // `Arc`, those three fields still are the components of the + // vector. + let vec = rebuild_boxed_slice(buf, offset, len).into_vec(); + let shared = Box::new(Shared { + _vec: vec, + // Initialize refcount to 2. One for this reference, and one + // for the new clone that will be returned from + // `shallow_clone`. + ref_cnt: AtomicUsize::new(2), + }); + + let shared = Box::into_raw(shared); + + // The pointer should be aligned, so this assert should + // always succeed. + debug_assert!( + 0 == (shared as usize & KIND_MASK), + "internal: Box should have an aligned pointer", + ); + + // Try compare & swapping the pointer into the `arc` field. + // `Release` is used synchronize with other threads that + // will load the `arc` field. + // + // If the `compare_and_swap` fails, then the thread lost the + // race to promote the buffer to shared. The `Acquire` + // ordering will synchronize with the `compare_and_swap` + // that happened in the other thread and the `Shared` + // pointed to by `actual` will be visible. + let actual = atom.compare_and_swap(ptr as _, shared as _, Ordering::AcqRel); + + if actual as usize == ptr as usize { + // The upgrade was successful, the new handle can be + // returned. + return Bytes { + ptr: offset, + len, + data: AtomicPtr::new(shared as _), + vtable: &SHARED_VTABLE, + }; + } + + // The upgrade failed, a concurrent clone happened. Release + // the allocation that was made in this thread, it will not + // be needed. + let shared = Box::from_raw(shared); + mem::forget(*shared); + + // Buffer already promoted to shared storage, so increment ref + // count. + shallow_clone_arc(actual as _, offset, len) +} + +unsafe fn release_shared(ptr: *mut Shared) { + // `Shared` storage... follow the drop steps from Arc. + if (*ptr).ref_cnt.fetch_sub(1, Ordering::Release) != 1 { + return; + } + + // This fence is needed to prevent reordering of use of the data and + // deletion of the data. Because it is marked `Release`, the decreasing + // of the reference count synchronizes with this `Acquire` fence. This + // means that use of the data happens before decreasing the reference + // count, which happens before this fence, which happens before the + // deletion of the data. + // + // As explained in the [Boost documentation][1], + // + // > It is important to enforce any possible access to the object in one + // > thread (through an existing reference) to *happen before* deleting + // > the object in a different thread. This is achieved by a "release" + // > operation after dropping a reference (any access to the object + // > through this reference must obviously happened before), and an + // > "acquire" operation before deleting the object. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + atomic::fence(Ordering::Acquire); + + // Drop the data + Box::from_raw(ptr); +} + +// compile-fails + +/// ```compile_fail +/// use bytes::Bytes; +/// #[deny(unused_must_use)] +/// { +/// let mut b1 = Bytes::from("hello world"); +/// b1.split_to(6); +/// } +/// ``` +fn _split_to_must_use() {} + +/// ```compile_fail +/// use bytes::Bytes; +/// #[deny(unused_must_use)] +/// { +/// let mut b1 = Bytes::from("hello world"); +/// b1.split_off(6); +/// } +/// ``` +fn _split_off_must_use() {} + +// fuzz tests +#[cfg(all(test, loom))] +mod fuzz { + use loom::sync::Arc; + use loom::thread; + + use super::Bytes; + #[test] + fn bytes_cloning_vec() { + loom::model(|| { + let a = Bytes::from(b"abcdefgh".to_vec()); + let addr = a.as_ptr() as usize; + + // test the Bytes::clone is Sync by putting it in an Arc + let a1 = Arc::new(a); + let a2 = a1.clone(); + + let t1 = thread::spawn(move || { + let b: Bytes = (*a1).clone(); + assert_eq!(b.as_ptr() as usize, addr); + }); + + let t2 = thread::spawn(move || { + let b: Bytes = (*a2).clone(); + assert_eq!(b.as_ptr() as usize, addr); + }); + + t1.join().unwrap(); + t2.join().unwrap(); + }); + } +} diff --git a/src/rust/vendor/bytes/src/bytes_mut.rs b/src/rust/vendor/bytes/src/bytes_mut.rs new file mode 100644 index 000000000..4d0585e80 --- /dev/null +++ b/src/rust/vendor/bytes/src/bytes_mut.rs @@ -0,0 +1,1576 @@ +use core::iter::{FromIterator, Iterator}; +use core::mem::{self, ManuallyDrop}; +use core::ops::{Deref, DerefMut}; +use core::ptr::{self, NonNull}; +use core::{cmp, fmt, hash, isize, slice, usize}; + +use alloc::{ + borrow::{Borrow, BorrowMut}, + boxed::Box, + string::String, + vec::Vec, +}; + +use crate::buf::IntoIter; +use crate::bytes::Vtable; +#[allow(unused)] +use crate::loom::sync::atomic::AtomicMut; +use crate::loom::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; +use crate::{Buf, BufMut, Bytes}; + +/// A unique reference to a contiguous slice of memory. +/// +/// `BytesMut` represents a unique view into a potentially shared memory region. +/// Given the uniqueness guarantee, owners of `BytesMut` handles are able to +/// mutate the memory. It is similar to a `Vec` but with less copies and +/// allocations. +/// +/// # Growth +/// +/// `BytesMut`'s `BufMut` implementation will implicitly grow its buffer as +/// necessary. However, explicitly reserving the required space up-front before +/// a series of inserts will be more efficient. +/// +/// # Examples +/// +/// ``` +/// use bytes::{BytesMut, BufMut}; +/// +/// let mut buf = BytesMut::with_capacity(64); +/// +/// buf.put_u8(b'h'); +/// buf.put_u8(b'e'); +/// buf.put(&b"llo"[..]); +/// +/// assert_eq!(&buf[..], b"hello"); +/// +/// // Freeze the buffer so that it can be shared +/// let a = buf.freeze(); +/// +/// // This does not allocate, instead `b` points to the same memory. +/// let b = a.clone(); +/// +/// assert_eq!(&a[..], b"hello"); +/// assert_eq!(&b[..], b"hello"); +/// ``` +pub struct BytesMut { + ptr: NonNull, + len: usize, + cap: usize, + data: *mut Shared, +} + +// Thread-safe reference-counted container for the shared storage. This mostly +// the same as `core::sync::Arc` but without the weak counter. The ref counting +// fns are based on the ones found in `std`. +// +// The main reason to use `Shared` instead of `core::sync::Arc` is that it ends +// up making the overall code simpler and easier to reason about. This is due to +// some of the logic around setting `Inner::arc` and other ways the `arc` field +// is used. Using `Arc` ended up requiring a number of funky transmutes and +// other shenanigans to make it work. +struct Shared { + vec: Vec, + original_capacity_repr: usize, + ref_count: AtomicUsize, +} + +// Buffer storage strategy flags. +const KIND_ARC: usize = 0b0; +const KIND_VEC: usize = 0b1; +const KIND_MASK: usize = 0b1; + +// The max original capacity value. Any `Bytes` allocated with a greater initial +// capacity will default to this. +const MAX_ORIGINAL_CAPACITY_WIDTH: usize = 17; +// The original capacity algorithm will not take effect unless the originally +// allocated capacity was at least 1kb in size. +const MIN_ORIGINAL_CAPACITY_WIDTH: usize = 10; +// The original capacity is stored in powers of 2 starting at 1kb to a max of +// 64kb. Representing it as such requires only 3 bits of storage. +const ORIGINAL_CAPACITY_MASK: usize = 0b11100; +const ORIGINAL_CAPACITY_OFFSET: usize = 2; + +// When the storage is in the `Vec` representation, the pointer can be advanced +// at most this value. This is due to the amount of storage available to track +// the offset is usize - number of KIND bits and number of ORIGINAL_CAPACITY +// bits. +const VEC_POS_OFFSET: usize = 5; +const MAX_VEC_POS: usize = usize::MAX >> VEC_POS_OFFSET; +const NOT_VEC_POS_MASK: usize = 0b11111; + +#[cfg(target_pointer_width = "64")] +const PTR_WIDTH: usize = 64; +#[cfg(target_pointer_width = "32")] +const PTR_WIDTH: usize = 32; + +/* + * + * ===== BytesMut ===== + * + */ + +impl BytesMut { + /// Creates a new `BytesMut` with the specified capacity. + /// + /// The returned `BytesMut` will be able to hold at least `capacity` bytes + /// without reallocating. + /// + /// It is important to note that this function does not specify the length + /// of the returned `BytesMut`, but only the capacity. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// + /// let mut bytes = BytesMut::with_capacity(64); + /// + /// // `bytes` contains no data, even though there is capacity + /// assert_eq!(bytes.len(), 0); + /// + /// bytes.put(&b"hello world"[..]); + /// + /// assert_eq!(&bytes[..], b"hello world"); + /// ``` + #[inline] + pub fn with_capacity(capacity: usize) -> BytesMut { + BytesMut::from_vec(Vec::with_capacity(capacity)) + } + + /// Creates a new `BytesMut` with default capacity. + /// + /// Resulting object has length 0 and unspecified capacity. + /// This function does not allocate. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// + /// let mut bytes = BytesMut::new(); + /// + /// assert_eq!(0, bytes.len()); + /// + /// bytes.reserve(2); + /// bytes.put_slice(b"xy"); + /// + /// assert_eq!(&b"xy"[..], &bytes[..]); + /// ``` + #[inline] + pub fn new() -> BytesMut { + BytesMut::with_capacity(0) + } + + /// Returns the number of bytes contained in this `BytesMut`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let b = BytesMut::from(&b"hello"[..]); + /// assert_eq!(b.len(), 5); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.len + } + + /// Returns true if the `BytesMut` has a length of 0. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let b = BytesMut::with_capacity(64); + /// assert!(b.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Returns the number of bytes the `BytesMut` can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let b = BytesMut::with_capacity(64); + /// assert_eq!(b.capacity(), 64); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.cap + } + + /// Converts `self` into an immutable `Bytes`. + /// + /// The conversion is zero cost and is used to indicate that the slice + /// referenced by the handle will no longer be mutated. Once the conversion + /// is done, the handle can be cloned and shared across threads. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// use std::thread; + /// + /// let mut b = BytesMut::with_capacity(64); + /// b.put(&b"hello world"[..]); + /// let b1 = b.freeze(); + /// let b2 = b1.clone(); + /// + /// let th = thread::spawn(move || { + /// assert_eq!(&b1[..], b"hello world"); + /// }); + /// + /// assert_eq!(&b2[..], b"hello world"); + /// th.join().unwrap(); + /// ``` + #[inline] + pub fn freeze(mut self) -> Bytes { + if self.kind() == KIND_VEC { + // Just re-use `Bytes` internal Vec vtable + unsafe { + let (off, _) = self.get_vec_pos(); + let vec = rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off); + mem::forget(self); + let mut b: Bytes = vec.into(); + b.advance(off); + b + } + } else { + debug_assert_eq!(self.kind(), KIND_ARC); + + let ptr = self.ptr.as_ptr(); + let len = self.len; + let data = AtomicPtr::new(self.data as _); + mem::forget(self); + unsafe { Bytes::with_vtable(ptr, len, data, &SHARED_VTABLE) } + } + } + + /// Splits the bytes into two at the given index. + /// + /// Afterwards `self` contains elements `[0, at)`, and the returned + /// `BytesMut` contains elements `[at, capacity)`. + /// + /// This is an `O(1)` operation that just increases the reference count + /// and sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut a = BytesMut::from(&b"hello world"[..]); + /// let mut b = a.split_off(5); + /// + /// a[0] = b'j'; + /// b[0] = b'!'; + /// + /// assert_eq!(&a[..], b"jello"); + /// assert_eq!(&b[..], b"!world"); + /// ``` + /// + /// # Panics + /// + /// Panics if `at > capacity`. + #[must_use = "consider BytesMut::truncate if you don't need the other half"] + pub fn split_off(&mut self, at: usize) -> BytesMut { + assert!( + at <= self.capacity(), + "split_off out of bounds: {:?} <= {:?}", + at, + self.capacity(), + ); + unsafe { + let mut other = self.shallow_clone(); + other.set_start(at); + self.set_end(at); + other + } + } + + /// Removes the bytes from the current view, returning them in a new + /// `BytesMut` handle. + /// + /// Afterwards, `self` will be empty, but will retain any additional + /// capacity that it had before the operation. This is identical to + /// `self.split_to(self.len())`. + /// + /// This is an `O(1)` operation that just increases the reference count and + /// sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// + /// let mut buf = BytesMut::with_capacity(1024); + /// buf.put(&b"hello world"[..]); + /// + /// let other = buf.split(); + /// + /// assert!(buf.is_empty()); + /// assert_eq!(1013, buf.capacity()); + /// + /// assert_eq!(other, b"hello world"[..]); + /// ``` + #[must_use = "consider BytesMut::advance(len()) if you don't need the other half"] + pub fn split(&mut self) -> BytesMut { + let len = self.len(); + self.split_to(len) + } + + /// Splits the buffer into two at the given index. + /// + /// Afterwards `self` contains elements `[at, len)`, and the returned `BytesMut` + /// contains elements `[0, at)`. + /// + /// This is an `O(1)` operation that just increases the reference count and + /// sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut a = BytesMut::from(&b"hello world"[..]); + /// let mut b = a.split_to(5); + /// + /// a[0] = b'!'; + /// b[0] = b'j'; + /// + /// assert_eq!(&a[..], b"!world"); + /// assert_eq!(&b[..], b"jello"); + /// ``` + /// + /// # Panics + /// + /// Panics if `at > len`. + #[must_use = "consider BytesMut::advance if you don't need the other half"] + pub fn split_to(&mut self, at: usize) -> BytesMut { + assert!( + at <= self.len(), + "split_to out of bounds: {:?} <= {:?}", + at, + self.len(), + ); + + unsafe { + let mut other = self.shallow_clone(); + other.set_end(at); + self.set_start(at); + other + } + } + + /// Shortens the buffer, keeping the first `len` bytes and dropping the + /// rest. + /// + /// If `len` is greater than the buffer's current length, this has no + /// effect. + /// + /// The [`split_off`] method can emulate `truncate`, but this causes the + /// excess bytes to be returned instead of dropped. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::from(&b"hello world"[..]); + /// buf.truncate(5); + /// assert_eq!(buf, b"hello"[..]); + /// ``` + /// + /// [`split_off`]: #method.split_off + pub fn truncate(&mut self, len: usize) { + if len <= self.len() { + unsafe { + self.set_len(len); + } + } + } + + /// Clears the buffer, removing all data. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::from(&b"hello world"[..]); + /// buf.clear(); + /// assert!(buf.is_empty()); + /// ``` + pub fn clear(&mut self) { + self.truncate(0); + } + + /// Resizes the buffer so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the buffer is extended by the + /// difference with each additional byte set to `value`. If `new_len` is + /// less than `len`, the buffer is simply truncated. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::new(); + /// + /// buf.resize(3, 0x1); + /// assert_eq!(&buf[..], &[0x1, 0x1, 0x1]); + /// + /// buf.resize(2, 0x2); + /// assert_eq!(&buf[..], &[0x1, 0x1]); + /// + /// buf.resize(4, 0x3); + /// assert_eq!(&buf[..], &[0x1, 0x1, 0x3, 0x3]); + /// ``` + pub fn resize(&mut self, new_len: usize, value: u8) { + let len = self.len(); + if new_len > len { + let additional = new_len - len; + self.reserve(additional); + unsafe { + let dst = self.bytes_mut().as_mut_ptr(); + ptr::write_bytes(dst, value, additional); + self.set_len(new_len); + } + } else { + self.truncate(new_len); + } + } + + /// Sets the length of the buffer. + /// + /// This will explicitly set the size of the buffer without actually + /// modifying the data, so it is up to the caller to ensure that the data + /// has been initialized. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut b = BytesMut::from(&b"hello world"[..]); + /// + /// unsafe { + /// b.set_len(5); + /// } + /// + /// assert_eq!(&b[..], b"hello"); + /// + /// unsafe { + /// b.set_len(11); + /// } + /// + /// assert_eq!(&b[..], b"hello world"); + /// ``` + pub unsafe fn set_len(&mut self, len: usize) { + debug_assert!(len <= self.cap, "set_len out of bounds"); + self.len = len; + } + + /// Reserves capacity for at least `additional` more bytes to be inserted + /// into the given `BytesMut`. + /// + /// More than `additional` bytes may be reserved in order to avoid frequent + /// reallocations. A call to `reserve` may result in an allocation. + /// + /// Before allocating new buffer space, the function will attempt to reclaim + /// space in the existing buffer. If the current handle references a small + /// view in the original buffer and all other handles have been dropped, + /// and the requested capacity is less than or equal to the existing + /// buffer's capacity, then the current view will be copied to the front of + /// the buffer and the handle will take ownership of the full buffer. + /// + /// # Examples + /// + /// In the following example, a new buffer is allocated. + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::from(&b"hello"[..]); + /// buf.reserve(64); + /// assert!(buf.capacity() >= 69); + /// ``` + /// + /// In the following example, the existing buffer is reclaimed. + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// + /// let mut buf = BytesMut::with_capacity(128); + /// buf.put(&[0; 64][..]); + /// + /// let ptr = buf.as_ptr(); + /// let other = buf.split(); + /// + /// assert!(buf.is_empty()); + /// assert_eq!(buf.capacity(), 64); + /// + /// drop(other); + /// buf.reserve(128); + /// + /// assert_eq!(buf.capacity(), 128); + /// assert_eq!(buf.as_ptr(), ptr); + /// ``` + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + #[inline] + pub fn reserve(&mut self, additional: usize) { + let len = self.len(); + let rem = self.capacity() - len; + + if additional <= rem { + // The handle can already store at least `additional` more bytes, so + // there is no further work needed to be done. + return; + } + + self.reserve_inner(additional); + } + + // In separate function to allow the short-circuits in `reserve` to + // be inline-able. Significant helps performance. + fn reserve_inner(&mut self, additional: usize) { + let len = self.len(); + let kind = self.kind(); + + if kind == KIND_VEC { + // If there's enough free space before the start of the buffer, then + // just copy the data backwards and reuse the already-allocated + // space. + // + // Otherwise, since backed by a vector, use `Vec::reserve` + unsafe { + let (off, prev) = self.get_vec_pos(); + + // Only reuse space if we stand to gain at least capacity/2 + // bytes of space back + if off >= additional && off >= (self.cap / 2) { + // There's space - reuse it + // + // Just move the pointer back to the start after copying + // data back. + let base_ptr = self.ptr.as_ptr().offset(-(off as isize)); + ptr::copy(self.ptr.as_ptr(), base_ptr, self.len); + self.ptr = vptr(base_ptr); + self.set_vec_pos(0, prev); + + // Length stays constant, but since we moved backwards we + // can gain capacity back. + self.cap += off; + } else { + // No space - allocate more + let mut v = + ManuallyDrop::new(rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off)); + v.reserve(additional); + + // Update the info + self.ptr = vptr(v.as_mut_ptr().offset(off as isize)); + self.len = v.len() - off; + self.cap = v.capacity() - off; + } + + return; + } + } + + debug_assert_eq!(kind, KIND_ARC); + let shared: *mut Shared = self.data as _; + + // Reserving involves abandoning the currently shared buffer and + // allocating a new vector with the requested capacity. + // + // Compute the new capacity + let mut new_cap = len.checked_add(additional).expect("overflow"); + + let original_capacity; + let original_capacity_repr; + + unsafe { + original_capacity_repr = (*shared).original_capacity_repr; + original_capacity = original_capacity_from_repr(original_capacity_repr); + + // First, try to reclaim the buffer. This is possible if the current + // handle is the only outstanding handle pointing to the buffer. + if (*shared).is_unique() { + // This is the only handle to the buffer. It can be reclaimed. + // However, before doing the work of copying data, check to make + // sure that the vector has enough capacity. + let v = &mut (*shared).vec; + + if v.capacity() >= new_cap { + // The capacity is sufficient, reclaim the buffer + let ptr = v.as_mut_ptr(); + + ptr::copy(self.ptr.as_ptr(), ptr, len); + + self.ptr = vptr(ptr); + self.cap = v.capacity(); + + return; + } + + // The vector capacity is not sufficient. The reserve request is + // asking for more than the initial buffer capacity. Allocate more + // than requested if `new_cap` is not much bigger than the current + // capacity. + // + // There are some situations, using `reserve_exact` that the + // buffer capacity could be below `original_capacity`, so do a + // check. + let double = v.capacity().checked_shl(1).unwrap_or(new_cap); + + new_cap = cmp::max(cmp::max(double, new_cap), original_capacity); + } else { + new_cap = cmp::max(new_cap, original_capacity); + } + } + + // Create a new vector to store the data + let mut v = ManuallyDrop::new(Vec::with_capacity(new_cap)); + + // Copy the bytes + v.extend_from_slice(self.as_ref()); + + // Release the shared handle. This must be done *after* the bytes are + // copied. + unsafe { release_shared(shared) }; + + // Update self + let data = (original_capacity_repr << ORIGINAL_CAPACITY_OFFSET) | KIND_VEC; + self.data = data as _; + self.ptr = vptr(v.as_mut_ptr()); + self.len = v.len(); + self.cap = v.capacity(); + } + + /// Appends given bytes to this `BytesMut`. + /// + /// If this `BytesMut` object does not have enough capacity, it is resized + /// first. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::with_capacity(0); + /// buf.extend_from_slice(b"aaabbb"); + /// buf.extend_from_slice(b"cccddd"); + /// + /// assert_eq!(b"aaabbbcccddd", &buf[..]); + /// ``` + pub fn extend_from_slice(&mut self, extend: &[u8]) { + let cnt = extend.len(); + self.reserve(cnt); + + unsafe { + let dst = self.maybe_uninit_bytes(); + // Reserved above + debug_assert!(dst.len() >= cnt); + + ptr::copy_nonoverlapping(extend.as_ptr(), dst.as_mut_ptr() as *mut u8, cnt); + } + + unsafe { + self.advance_mut(cnt); + } + } + + /// Absorbs a `BytesMut` that was previously split off. + /// + /// If the two `BytesMut` objects were previously contiguous, i.e., if + /// `other` was created by calling `split_off` on this `BytesMut`, then + /// this is an `O(1)` operation that just decreases a reference + /// count and sets a few indices. Otherwise this method degenerates to + /// `self.extend_from_slice(other.as_ref())`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::with_capacity(64); + /// buf.extend_from_slice(b"aaabbbcccddd"); + /// + /// let split = buf.split_off(6); + /// assert_eq!(b"aaabbb", &buf[..]); + /// assert_eq!(b"cccddd", &split[..]); + /// + /// buf.unsplit(split); + /// assert_eq!(b"aaabbbcccddd", &buf[..]); + /// ``` + pub fn unsplit(&mut self, other: BytesMut) { + if self.is_empty() { + *self = other; + return; + } + + if let Err(other) = self.try_unsplit(other) { + self.extend_from_slice(other.as_ref()); + } + } + + // private + + // For now, use a `Vec` to manage the memory for us, but we may want to + // change that in the future to some alternate allocator strategy. + // + // Thus, we don't expose an easy way to construct from a `Vec` since an + // internal change could make a simple pattern (`BytesMut::from(vec)`) + // suddenly a lot more expensive. + #[inline] + pub(crate) fn from_vec(mut vec: Vec) -> BytesMut { + let ptr = vptr(vec.as_mut_ptr()); + let len = vec.len(); + let cap = vec.capacity(); + mem::forget(vec); + + let original_capacity_repr = original_capacity_to_repr(cap); + let data = (original_capacity_repr << ORIGINAL_CAPACITY_OFFSET) | KIND_VEC; + + BytesMut { + ptr, + len, + cap, + data: data as *mut _, + } + } + + #[inline] + fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) } + } + + #[inline] + fn as_slice_mut(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) } + } + + unsafe fn set_start(&mut self, start: usize) { + // Setting the start to 0 is a no-op, so return early if this is the + // case. + if start == 0 { + return; + } + + debug_assert!(start <= self.cap, "internal: set_start out of bounds"); + + let kind = self.kind(); + + if kind == KIND_VEC { + // Setting the start when in vec representation is a little more + // complicated. First, we have to track how far ahead the + // "start" of the byte buffer from the beginning of the vec. We + // also have to ensure that we don't exceed the maximum shift. + let (mut pos, prev) = self.get_vec_pos(); + pos += start; + + if pos <= MAX_VEC_POS { + self.set_vec_pos(pos, prev); + } else { + // The repr must be upgraded to ARC. This will never happen + // on 64 bit systems and will only happen on 32 bit systems + // when shifting past 134,217,727 bytes. As such, we don't + // worry too much about performance here. + self.promote_to_shared(/*ref_count = */ 1); + } + } + + // Updating the start of the view is setting `ptr` to point to the + // new start and updating the `len` field to reflect the new length + // of the view. + self.ptr = vptr(self.ptr.as_ptr().offset(start as isize)); + + if self.len >= start { + self.len -= start; + } else { + self.len = 0; + } + + self.cap -= start; + } + + unsafe fn set_end(&mut self, end: usize) { + debug_assert_eq!(self.kind(), KIND_ARC); + assert!(end <= self.cap, "set_end out of bounds"); + + self.cap = end; + self.len = cmp::min(self.len, end); + } + + fn try_unsplit(&mut self, other: BytesMut) -> Result<(), BytesMut> { + if other.is_empty() { + return Ok(()); + } + + let ptr = unsafe { self.ptr.as_ptr().offset(self.len as isize) }; + if ptr == other.ptr.as_ptr() + && self.kind() == KIND_ARC + && other.kind() == KIND_ARC + && self.data == other.data + { + // Contiguous blocks, just combine directly + self.len += other.len; + self.cap += other.cap; + Ok(()) + } else { + Err(other) + } + } + + #[inline] + fn kind(&self) -> usize { + self.data as usize & KIND_MASK + } + + unsafe fn promote_to_shared(&mut self, ref_cnt: usize) { + debug_assert_eq!(self.kind(), KIND_VEC); + debug_assert!(ref_cnt == 1 || ref_cnt == 2); + + let original_capacity_repr = + (self.data as usize & ORIGINAL_CAPACITY_MASK) >> ORIGINAL_CAPACITY_OFFSET; + + // The vec offset cannot be concurrently mutated, so there + // should be no danger reading it. + let off = (self.data as usize) >> VEC_POS_OFFSET; + + // First, allocate a new `Shared` instance containing the + // `Vec` fields. It's important to note that `ptr`, `len`, + // and `cap` cannot be mutated without having `&mut self`. + // This means that these fields will not be concurrently + // updated and since the buffer hasn't been promoted to an + // `Arc`, those three fields still are the components of the + // vector. + let shared = Box::new(Shared { + vec: rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off), + original_capacity_repr, + ref_count: AtomicUsize::new(ref_cnt), + }); + + let shared = Box::into_raw(shared); + + // The pointer should be aligned, so this assert should + // always succeed. + debug_assert_eq!(shared as usize & KIND_MASK, KIND_ARC); + + self.data = shared as _; + } + + /// Makes an exact shallow clone of `self`. + /// + /// The kind of `self` doesn't matter, but this is unsafe + /// because the clone will have the same offsets. You must + /// be sure the returned value to the user doesn't allow + /// two views into the same range. + #[inline] + unsafe fn shallow_clone(&mut self) -> BytesMut { + if self.kind() == KIND_ARC { + increment_shared(self.data); + ptr::read(self) + } else { + self.promote_to_shared(/*ref_count = */ 2); + ptr::read(self) + } + } + + #[inline] + unsafe fn get_vec_pos(&mut self) -> (usize, usize) { + debug_assert_eq!(self.kind(), KIND_VEC); + + let prev = self.data as usize; + (prev >> VEC_POS_OFFSET, prev) + } + + #[inline] + unsafe fn set_vec_pos(&mut self, pos: usize, prev: usize) { + debug_assert_eq!(self.kind(), KIND_VEC); + debug_assert!(pos <= MAX_VEC_POS); + + self.data = ((pos << VEC_POS_OFFSET) | (prev & NOT_VEC_POS_MASK)) as *mut _; + } + + #[inline] + fn maybe_uninit_bytes(&mut self) -> &mut [mem::MaybeUninit] { + unsafe { + let ptr = self.ptr.as_ptr().offset(self.len as isize); + let len = self.cap - self.len; + + slice::from_raw_parts_mut(ptr as *mut mem::MaybeUninit, len) + } + } +} + +impl Drop for BytesMut { + fn drop(&mut self) { + let kind = self.kind(); + + if kind == KIND_VEC { + unsafe { + let (off, _) = self.get_vec_pos(); + + // Vector storage, free the vector + let _ = rebuild_vec(self.ptr.as_ptr(), self.len, self.cap, off); + } + } else if kind == KIND_ARC { + unsafe { release_shared(self.data as _) }; + } + } +} + +impl Buf for BytesMut { + #[inline] + fn remaining(&self) -> usize { + self.len() + } + + #[inline] + fn bytes(&self) -> &[u8] { + self.as_slice() + } + + #[inline] + fn advance(&mut self, cnt: usize) { + assert!( + cnt <= self.remaining(), + "cannot advance past `remaining`: {:?} <= {:?}", + cnt, + self.remaining(), + ); + unsafe { + self.set_start(cnt); + } + } + + fn to_bytes(&mut self) -> crate::Bytes { + self.split().freeze() + } +} + +impl BufMut for BytesMut { + #[inline] + fn remaining_mut(&self) -> usize { + usize::MAX - self.len() + } + + #[inline] + unsafe fn advance_mut(&mut self, cnt: usize) { + let new_len = self.len() + cnt; + assert!( + new_len <= self.cap, + "new_len = {}; capacity = {}", + new_len, + self.cap + ); + self.len = new_len; + } + + #[inline] + fn bytes_mut(&mut self) -> &mut [mem::MaybeUninit] { + if self.capacity() == self.len() { + self.reserve(64); + } + self.maybe_uninit_bytes() + } + + // Specialize these methods so they can skip checking `remaining_mut` + // and `advance_mut`. + + fn put(&mut self, mut src: T) + where + Self: Sized, + { + while src.has_remaining() { + let s = src.bytes(); + let l = s.len(); + self.extend_from_slice(s); + src.advance(l); + } + } + + fn put_slice(&mut self, src: &[u8]) { + self.extend_from_slice(src); + } +} + +impl AsRef<[u8]> for BytesMut { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_slice() + } +} + +impl Deref for BytesMut { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.as_ref() + } +} + +impl AsMut<[u8]> for BytesMut { + fn as_mut(&mut self) -> &mut [u8] { + self.as_slice_mut() + } +} + +impl DerefMut for BytesMut { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + self.as_mut() + } +} + +impl<'a> From<&'a [u8]> for BytesMut { + fn from(src: &'a [u8]) -> BytesMut { + BytesMut::from_vec(src.to_vec()) + } +} + +impl<'a> From<&'a str> for BytesMut { + fn from(src: &'a str) -> BytesMut { + BytesMut::from(src.as_bytes()) + } +} + +impl From for Bytes { + fn from(src: BytesMut) -> Bytes { + src.freeze() + } +} + +impl PartialEq for BytesMut { + fn eq(&self, other: &BytesMut) -> bool { + self.as_slice() == other.as_slice() + } +} + +impl PartialOrd for BytesMut { + fn partial_cmp(&self, other: &BytesMut) -> Option { + self.as_slice().partial_cmp(other.as_slice()) + } +} + +impl Ord for BytesMut { + fn cmp(&self, other: &BytesMut) -> cmp::Ordering { + self.as_slice().cmp(other.as_slice()) + } +} + +impl Eq for BytesMut {} + +impl Default for BytesMut { + #[inline] + fn default() -> BytesMut { + BytesMut::new() + } +} + +impl hash::Hash for BytesMut { + fn hash(&self, state: &mut H) + where + H: hash::Hasher, + { + let s: &[u8] = self.as_ref(); + s.hash(state); + } +} + +impl Borrow<[u8]> for BytesMut { + fn borrow(&self) -> &[u8] { + self.as_ref() + } +} + +impl BorrowMut<[u8]> for BytesMut { + fn borrow_mut(&mut self) -> &mut [u8] { + self.as_mut() + } +} + +impl fmt::Write for BytesMut { + #[inline] + fn write_str(&mut self, s: &str) -> fmt::Result { + if self.remaining_mut() >= s.len() { + self.put_slice(s.as_bytes()); + Ok(()) + } else { + Err(fmt::Error) + } + } + + #[inline] + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result { + fmt::write(self, args) + } +} + +impl Clone for BytesMut { + fn clone(&self) -> BytesMut { + BytesMut::from(&self[..]) + } +} + +impl IntoIterator for BytesMut { + type Item = u8; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self) + } +} + +impl<'a> IntoIterator for &'a BytesMut { + type Item = &'a u8; + type IntoIter = core::slice::Iter<'a, u8>; + + fn into_iter(self) -> Self::IntoIter { + self.as_ref().into_iter() + } +} + +impl Extend for BytesMut { + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + let iter = iter.into_iter(); + + let (lower, _) = iter.size_hint(); + self.reserve(lower); + + // TODO: optimize + // 1. If self.kind() == KIND_VEC, use Vec::extend + // 2. Make `reserve` inline-able + for b in iter { + self.reserve(1); + self.put_u8(b); + } + } +} + +impl<'a> Extend<&'a u8> for BytesMut { + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + self.extend(iter.into_iter().map(|b| *b)) + } +} + +impl FromIterator for BytesMut { + fn from_iter>(into_iter: T) -> Self { + BytesMut::from_vec(Vec::from_iter(into_iter)) + } +} + +impl<'a> FromIterator<&'a u8> for BytesMut { + fn from_iter>(into_iter: T) -> Self { + BytesMut::from_iter(into_iter.into_iter().map(|b| *b)) + } +} + +/* + * + * ===== Inner ===== + * + */ + +unsafe fn increment_shared(ptr: *mut Shared) { + let old_size = (*ptr).ref_count.fetch_add(1, Ordering::Relaxed); + + if old_size > isize::MAX as usize { + crate::abort(); + } +} + +unsafe fn release_shared(ptr: *mut Shared) { + // `Shared` storage... follow the drop steps from Arc. + if (*ptr).ref_count.fetch_sub(1, Ordering::Release) != 1 { + return; + } + + // This fence is needed to prevent reordering of use of the data and + // deletion of the data. Because it is marked `Release`, the decreasing + // of the reference count synchronizes with this `Acquire` fence. This + // means that use of the data happens before decreasing the reference + // count, which happens before this fence, which happens before the + // deletion of the data. + // + // As explained in the [Boost documentation][1], + // + // > It is important to enforce any possible access to the object in one + // > thread (through an existing reference) to *happen before* deleting + // > the object in a different thread. This is achieved by a "release" + // > operation after dropping a reference (any access to the object + // > through this reference must obviously happened before), and an + // > "acquire" operation before deleting the object. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + atomic::fence(Ordering::Acquire); + + // Drop the data + Box::from_raw(ptr); +} + +impl Shared { + fn is_unique(&self) -> bool { + // The goal is to check if the current handle is the only handle + // that currently has access to the buffer. This is done by + // checking if the `ref_count` is currently 1. + // + // The `Acquire` ordering synchronizes with the `Release` as + // part of the `fetch_sub` in `release_shared`. The `fetch_sub` + // operation guarantees that any mutations done in other threads + // are ordered before the `ref_count` is decremented. As such, + // this `Acquire` will guarantee that those mutations are + // visible to the current thread. + self.ref_count.load(Ordering::Acquire) == 1 + } +} + +fn original_capacity_to_repr(cap: usize) -> usize { + let width = PTR_WIDTH - ((cap >> MIN_ORIGINAL_CAPACITY_WIDTH).leading_zeros() as usize); + cmp::min( + width, + MAX_ORIGINAL_CAPACITY_WIDTH - MIN_ORIGINAL_CAPACITY_WIDTH, + ) +} + +fn original_capacity_from_repr(repr: usize) -> usize { + if repr == 0 { + return 0; + } + + 1 << (repr + (MIN_ORIGINAL_CAPACITY_WIDTH - 1)) +} + +/* +#[test] +fn test_original_capacity_to_repr() { + assert_eq!(original_capacity_to_repr(0), 0); + + let max_width = 32; + + for width in 1..(max_width + 1) { + let cap = 1 << width - 1; + + let expected = if width < MIN_ORIGINAL_CAPACITY_WIDTH { + 0 + } else if width < MAX_ORIGINAL_CAPACITY_WIDTH { + width - MIN_ORIGINAL_CAPACITY_WIDTH + } else { + MAX_ORIGINAL_CAPACITY_WIDTH - MIN_ORIGINAL_CAPACITY_WIDTH + }; + + assert_eq!(original_capacity_to_repr(cap), expected); + + if width > 1 { + assert_eq!(original_capacity_to_repr(cap + 1), expected); + } + + // MIN_ORIGINAL_CAPACITY_WIDTH must be bigger than 7 to pass tests below + if width == MIN_ORIGINAL_CAPACITY_WIDTH + 1 { + assert_eq!(original_capacity_to_repr(cap - 24), expected - 1); + assert_eq!(original_capacity_to_repr(cap + 76), expected); + } else if width == MIN_ORIGINAL_CAPACITY_WIDTH + 2 { + assert_eq!(original_capacity_to_repr(cap - 1), expected - 1); + assert_eq!(original_capacity_to_repr(cap - 48), expected - 1); + } + } +} + +#[test] +fn test_original_capacity_from_repr() { + assert_eq!(0, original_capacity_from_repr(0)); + + let min_cap = 1 << MIN_ORIGINAL_CAPACITY_WIDTH; + + assert_eq!(min_cap, original_capacity_from_repr(1)); + assert_eq!(min_cap * 2, original_capacity_from_repr(2)); + assert_eq!(min_cap * 4, original_capacity_from_repr(3)); + assert_eq!(min_cap * 8, original_capacity_from_repr(4)); + assert_eq!(min_cap * 16, original_capacity_from_repr(5)); + assert_eq!(min_cap * 32, original_capacity_from_repr(6)); + assert_eq!(min_cap * 64, original_capacity_from_repr(7)); +} +*/ + +unsafe impl Send for BytesMut {} +unsafe impl Sync for BytesMut {} + +/* + * + * ===== PartialEq / PartialOrd ===== + * + */ + +impl PartialEq<[u8]> for BytesMut { + fn eq(&self, other: &[u8]) -> bool { + &**self == other + } +} + +impl PartialOrd<[u8]> for BytesMut { + fn partial_cmp(&self, other: &[u8]) -> Option { + (**self).partial_cmp(other) + } +} + +impl PartialEq for [u8] { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for [u8] { + fn partial_cmp(&self, other: &BytesMut) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self, other) + } +} + +impl PartialEq for BytesMut { + fn eq(&self, other: &str) -> bool { + &**self == other.as_bytes() + } +} + +impl PartialOrd for BytesMut { + fn partial_cmp(&self, other: &str) -> Option { + (**self).partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for str { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for str { + fn partial_cmp(&self, other: &BytesMut) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self.as_bytes(), other) + } +} + +impl PartialEq> for BytesMut { + fn eq(&self, other: &Vec) -> bool { + *self == &other[..] + } +} + +impl PartialOrd> for BytesMut { + fn partial_cmp(&self, other: &Vec) -> Option { + (**self).partial_cmp(&other[..]) + } +} + +impl PartialEq for Vec { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for Vec { + fn partial_cmp(&self, other: &BytesMut) -> Option { + other.partial_cmp(self) + } +} + +impl PartialEq for BytesMut { + fn eq(&self, other: &String) -> bool { + *self == &other[..] + } +} + +impl PartialOrd for BytesMut { + fn partial_cmp(&self, other: &String) -> Option { + (**self).partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for String { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for String { + fn partial_cmp(&self, other: &BytesMut) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self.as_bytes(), other) + } +} + +impl<'a, T: ?Sized> PartialEq<&'a T> for BytesMut +where + BytesMut: PartialEq, +{ + fn eq(&self, other: &&'a T) -> bool { + *self == **other + } +} + +impl<'a, T: ?Sized> PartialOrd<&'a T> for BytesMut +where + BytesMut: PartialOrd, +{ + fn partial_cmp(&self, other: &&'a T) -> Option { + self.partial_cmp(*other) + } +} + +impl PartialEq for &[u8] { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for &[u8] { + fn partial_cmp(&self, other: &BytesMut) -> Option { + <[u8] as PartialOrd<[u8]>>::partial_cmp(self, other) + } +} + +impl PartialEq for &str { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for &str { + fn partial_cmp(&self, other: &BytesMut) -> Option { + other.partial_cmp(self) + } +} + +impl PartialEq for Bytes { + fn eq(&self, other: &BytesMut) -> bool { + &other[..] == &self[..] + } +} + +impl PartialEq for BytesMut { + fn eq(&self, other: &Bytes) -> bool { + &other[..] == &self[..] + } +} + +fn vptr(ptr: *mut u8) -> NonNull { + if cfg!(debug_assertions) { + NonNull::new(ptr).expect("Vec pointer should be non-null") + } else { + unsafe { NonNull::new_unchecked(ptr) } + } +} + +unsafe fn rebuild_vec(ptr: *mut u8, mut len: usize, mut cap: usize, off: usize) -> Vec { + let ptr = ptr.offset(-(off as isize)); + len += off; + cap += off; + + Vec::from_raw_parts(ptr, len, cap) +} + +// ===== impl SharedVtable ===== + +static SHARED_VTABLE: Vtable = Vtable { + clone: shared_v_clone, + drop: shared_v_drop, +}; + +unsafe fn shared_v_clone(data: &AtomicPtr<()>, ptr: *const u8, len: usize) -> Bytes { + let shared = data.load(Ordering::Acquire) as *mut Shared; + increment_shared(shared); + + let data = AtomicPtr::new(shared as _); + Bytes::with_vtable(ptr, len, data, &SHARED_VTABLE) +} + +unsafe fn shared_v_drop(data: &mut AtomicPtr<()>, _ptr: *const u8, _len: usize) { + data.with_mut(|shared| { + release_shared(*shared as *mut Shared); + }); +} + +// compile-fails + +/// ```compile_fail +/// use bytes::BytesMut; +/// #[deny(unused_must_use)] +/// { +/// let mut b1 = BytesMut::from("hello world"); +/// b1.split_to(6); +/// } +/// ``` +fn _split_to_must_use() {} + +/// ```compile_fail +/// use bytes::BytesMut; +/// #[deny(unused_must_use)] +/// { +/// let mut b1 = BytesMut::from("hello world"); +/// b1.split_off(6); +/// } +/// ``` +fn _split_off_must_use() {} + +/// ```compile_fail +/// use bytes::BytesMut; +/// #[deny(unused_must_use)] +/// { +/// let mut b1 = BytesMut::from("hello world"); +/// b1.split(); +/// } +/// ``` +fn _split_must_use() {} + +// fuzz tests +#[cfg(all(test, loom))] +mod fuzz { + use loom::sync::Arc; + use loom::thread; + + use super::BytesMut; + use crate::Bytes; + + #[test] + fn bytes_mut_cloning_frozen() { + loom::model(|| { + let a = BytesMut::from(&b"abcdefgh"[..]).split().freeze(); + let addr = a.as_ptr() as usize; + + // test the Bytes::clone is Sync by putting it in an Arc + let a1 = Arc::new(a); + let a2 = a1.clone(); + + let t1 = thread::spawn(move || { + let b: Bytes = (*a1).clone(); + assert_eq!(b.as_ptr() as usize, addr); + }); + + let t2 = thread::spawn(move || { + let b: Bytes = (*a2).clone(); + assert_eq!(b.as_ptr() as usize, addr); + }); + + t1.join().unwrap(); + t2.join().unwrap(); + }); + } +} diff --git a/src/rust/vendor/bytes/src/fmt/debug.rs b/src/rust/vendor/bytes/src/fmt/debug.rs new file mode 100644 index 000000000..a8545514e --- /dev/null +++ b/src/rust/vendor/bytes/src/fmt/debug.rs @@ -0,0 +1,49 @@ +use core::fmt::{Debug, Formatter, Result}; + +use super::BytesRef; +use crate::{Bytes, BytesMut}; + +/// Alternative implementation of `std::fmt::Debug` for byte slice. +/// +/// Standard `Debug` implementation for `[u8]` is comma separated +/// list of numbers. Since large amount of byte strings are in fact +/// ASCII strings or contain a lot of ASCII strings (e. g. HTTP), +/// it is convenient to print strings as ASCII when possible. +impl Debug for BytesRef<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "b\"")?; + for &b in self.0 { + // https://doc.rust-lang.org/reference/tokens.html#byte-escapes + if b == b'\n' { + write!(f, "\\n")?; + } else if b == b'\r' { + write!(f, "\\r")?; + } else if b == b'\t' { + write!(f, "\\t")?; + } else if b == b'\\' || b == b'"' { + write!(f, "\\{}", b as char)?; + } else if b == b'\0' { + write!(f, "\\0")?; + // ASCII printable + } else if b >= 0x20 && b < 0x7f { + write!(f, "{}", b as char)?; + } else { + write!(f, "\\x{:02x}", b)?; + } + } + write!(f, "\"")?; + Ok(()) + } +} + +impl Debug for Bytes { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + Debug::fmt(&BytesRef(&self.as_ref()), f) + } +} + +impl Debug for BytesMut { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + Debug::fmt(&BytesRef(&self.as_ref()), f) + } +} diff --git a/src/rust/vendor/bytes/src/fmt/hex.rs b/src/rust/vendor/bytes/src/fmt/hex.rs new file mode 100644 index 000000000..97a749a33 --- /dev/null +++ b/src/rust/vendor/bytes/src/fmt/hex.rs @@ -0,0 +1,37 @@ +use core::fmt::{Formatter, LowerHex, Result, UpperHex}; + +use super::BytesRef; +use crate::{Bytes, BytesMut}; + +impl LowerHex for BytesRef<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + for &b in self.0 { + write!(f, "{:02x}", b)?; + } + Ok(()) + } +} + +impl UpperHex for BytesRef<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + for &b in self.0 { + write!(f, "{:02X}", b)?; + } + Ok(()) + } +} + +macro_rules! hex_impl { + ($tr:ident, $ty:ty) => { + impl $tr for $ty { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + $tr::fmt(&BytesRef(self.as_ref()), f) + } + } + }; +} + +hex_impl!(LowerHex, Bytes); +hex_impl!(LowerHex, BytesMut); +hex_impl!(UpperHex, Bytes); +hex_impl!(UpperHex, BytesMut); diff --git a/src/rust/vendor/bytes/src/fmt/mod.rs b/src/rust/vendor/bytes/src/fmt/mod.rs new file mode 100644 index 000000000..676d15fc2 --- /dev/null +++ b/src/rust/vendor/bytes/src/fmt/mod.rs @@ -0,0 +1,5 @@ +mod debug; +mod hex; + +/// `BytesRef` is not a part of public API of bytes crate. +struct BytesRef<'a>(&'a [u8]); diff --git a/src/rust/vendor/bytes/src/lib.rs b/src/rust/vendor/bytes/src/lib.rs new file mode 100644 index 000000000..accbf71ce --- /dev/null +++ b/src/rust/vendor/bytes/src/lib.rs @@ -0,0 +1,122 @@ +#![deny( + warnings, + missing_docs, + missing_debug_implementations, + rust_2018_idioms +)] +#![doc(test( + no_crate_inject, + attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) +))] +#![doc(html_root_url = "https://docs.rs/bytes/0.5.5")] +#![no_std] + +//! Provides abstractions for working with bytes. +//! +//! The `bytes` crate provides an efficient byte buffer structure +//! ([`Bytes`](struct.Bytes.html)) and traits for working with buffer +//! implementations ([`Buf`], [`BufMut`]). +//! +//! [`Buf`]: trait.Buf.html +//! [`BufMut`]: trait.BufMut.html +//! +//! # `Bytes` +//! +//! `Bytes` is an efficient container for storing and operating on contiguous +//! slices of memory. It is intended for use primarily in networking code, but +//! could have applications elsewhere as well. +//! +//! `Bytes` values facilitate zero-copy network programming by allowing multiple +//! `Bytes` objects to point to the same underlying memory. This is managed by +//! using a reference count to track when the memory is no longer needed and can +//! be freed. +//! +//! A `Bytes` handle can be created directly from an existing byte store (such as `&[u8]` +//! or `Vec`), but usually a `BytesMut` is used first and written to. For +//! example: +//! +//! ```rust +//! use bytes::{BytesMut, BufMut}; +//! +//! let mut buf = BytesMut::with_capacity(1024); +//! buf.put(&b"hello world"[..]); +//! buf.put_u16(1234); +//! +//! let a = buf.split(); +//! assert_eq!(a, b"hello world\x04\xD2"[..]); +//! +//! buf.put(&b"goodbye world"[..]); +//! +//! let b = buf.split(); +//! assert_eq!(b, b"goodbye world"[..]); +//! +//! assert_eq!(buf.capacity(), 998); +//! ``` +//! +//! In the above example, only a single buffer of 1024 is allocated. The handles +//! `a` and `b` will share the underlying buffer and maintain indices tracking +//! the view into the buffer represented by the handle. +//! +//! See the [struct docs] for more details. +//! +//! [struct docs]: struct.Bytes.html +//! +//! # `Buf`, `BufMut` +//! +//! These two traits provide read and write access to buffers. The underlying +//! storage may or may not be in contiguous memory. For example, `Bytes` is a +//! buffer that guarantees contiguous memory, but a [rope] stores the bytes in +//! disjoint chunks. `Buf` and `BufMut` maintain cursors tracking the current +//! position in the underlying byte storage. When bytes are read or written, the +//! cursor is advanced. +//! +//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure) +//! +//! ## Relation with `Read` and `Write` +//! +//! At first glance, it may seem that `Buf` and `BufMut` overlap in +//! functionality with `std::io::Read` and `std::io::Write`. However, they +//! serve different purposes. A buffer is the value that is provided as an +//! argument to `Read::read` and `Write::write`. `Read` and `Write` may then +//! perform a syscall, which has the potential of failing. Operations on `Buf` +//! and `BufMut` are infallible. + +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +pub mod buf; +pub use crate::buf::{Buf, BufMut}; + +mod bytes; +mod bytes_mut; +mod fmt; +mod loom; +pub use crate::bytes::Bytes; +pub use crate::bytes_mut::BytesMut; + +// Optional Serde support +#[cfg(feature = "serde")] +mod serde; + +#[inline(never)] +#[cold] +fn abort() -> ! { + #[cfg(feature = "std")] + { + std::process::abort(); + } + + #[cfg(not(feature = "std"))] + { + struct Abort; + impl Drop for Abort { + fn drop(&mut self) { + panic!(); + } + } + let _a = Abort; + panic!("abort"); + } +} diff --git a/src/rust/vendor/bytes/src/loom.rs b/src/rust/vendor/bytes/src/loom.rs new file mode 100644 index 000000000..1cae8812e --- /dev/null +++ b/src/rust/vendor/bytes/src/loom.rs @@ -0,0 +1,30 @@ +#[cfg(not(all(test, loom)))] +pub(crate) mod sync { + pub(crate) mod atomic { + pub(crate) use core::sync::atomic::{fence, AtomicPtr, AtomicUsize, Ordering}; + + pub(crate) trait AtomicMut { + fn with_mut(&mut self, f: F) -> R + where + F: FnOnce(&mut *mut T) -> R; + } + + impl AtomicMut for AtomicPtr { + fn with_mut(&mut self, f: F) -> R + where + F: FnOnce(&mut *mut T) -> R, + { + f(self.get_mut()) + } + } + } +} + +#[cfg(all(test, loom))] +pub(crate) mod sync { + pub(crate) mod atomic { + pub(crate) use loom::sync::atomic::{fence, AtomicPtr, AtomicUsize, Ordering}; + + pub(crate) trait AtomicMut {} + } +} diff --git a/src/rust/vendor/bytes/src/serde.rs b/src/rust/vendor/bytes/src/serde.rs new file mode 100644 index 000000000..0a5bd144a --- /dev/null +++ b/src/rust/vendor/bytes/src/serde.rs @@ -0,0 +1,89 @@ +use super::{Bytes, BytesMut}; +use alloc::string::String; +use alloc::vec::Vec; +use core::{cmp, fmt}; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +macro_rules! serde_impl { + ($ty:ident, $visitor_ty:ident, $from_slice:ident, $from_vec:ident) => { + impl Serialize for $ty { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(&self) + } + } + + struct $visitor_ty; + + impl<'de> de::Visitor<'de> for $visitor_ty { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("byte array") + } + + #[inline] + fn visit_seq(self, mut seq: V) -> Result + where + V: de::SeqAccess<'de>, + { + let len = cmp::min(seq.size_hint().unwrap_or(0), 4096); + let mut values: Vec = Vec::with_capacity(len); + + while let Some(value) = seq.next_element()? { + values.push(value); + } + + Ok($ty::$from_vec(values)) + } + + #[inline] + fn visit_bytes(self, v: &[u8]) -> Result + where + E: de::Error, + { + Ok($ty::$from_slice(v)) + } + + #[inline] + fn visit_byte_buf(self, v: Vec) -> Result + where + E: de::Error, + { + Ok($ty::$from_vec(v)) + } + + #[inline] + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + Ok($ty::$from_slice(v.as_bytes())) + } + + #[inline] + fn visit_string(self, v: String) -> Result + where + E: de::Error, + { + Ok($ty::$from_vec(v.into_bytes())) + } + } + + impl<'de> Deserialize<'de> for $ty { + #[inline] + fn deserialize(deserializer: D) -> Result<$ty, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_byte_buf($visitor_ty) + } + } + }; +} + +serde_impl!(Bytes, BytesVisitor, copy_from_slice, from); +serde_impl!(BytesMut, BytesMutVisitor, from, from_vec); diff --git a/src/rust/vendor/bytes/tests/test_buf.rs b/src/rust/vendor/bytes/tests/test_buf.rs new file mode 100644 index 000000000..26b95aee8 --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_buf.rs @@ -0,0 +1,103 @@ +#![deny(warnings, rust_2018_idioms)] + +use bytes::Buf; +#[cfg(feature = "std")] +use std::io::IoSlice; + +#[test] +fn test_fresh_cursor_vec() { + let mut buf = &b"hello"[..]; + + assert_eq!(buf.remaining(), 5); + assert_eq!(buf.bytes(), b"hello"); + + buf.advance(2); + + assert_eq!(buf.remaining(), 3); + assert_eq!(buf.bytes(), b"llo"); + + buf.advance(3); + + assert_eq!(buf.remaining(), 0); + assert_eq!(buf.bytes(), b""); +} + +#[test] +fn test_get_u8() { + let mut buf = &b"\x21zomg"[..]; + assert_eq!(0x21, buf.get_u8()); +} + +#[test] +fn test_get_u16() { + let mut buf = &b"\x21\x54zomg"[..]; + assert_eq!(0x2154, buf.get_u16()); + let mut buf = &b"\x21\x54zomg"[..]; + assert_eq!(0x5421, buf.get_u16_le()); +} + +#[test] +#[should_panic] +fn test_get_u16_buffer_underflow() { + let mut buf = &b"\x21"[..]; + buf.get_u16(); +} + +#[cfg(feature = "std")] +#[test] +fn test_bufs_vec() { + let buf = &b"hello world"[..]; + + let b1: &[u8] = &mut []; + let b2: &[u8] = &mut []; + + let mut dst = [IoSlice::new(b1), IoSlice::new(b2)]; + + assert_eq!(1, buf.bytes_vectored(&mut dst[..])); +} + +#[test] +fn test_vec_deque() { + use std::collections::VecDeque; + + let mut buffer: VecDeque = VecDeque::new(); + buffer.extend(b"hello world"); + assert_eq!(11, buffer.remaining()); + assert_eq!(b"hello world", buffer.bytes()); + buffer.advance(6); + assert_eq!(b"world", buffer.bytes()); + buffer.extend(b" piece"); + let mut out = [0; 11]; + buffer.copy_to_slice(&mut out); + assert_eq!(b"world piece", &out[..]); +} + +#[test] +fn test_deref_buf_forwards() { + struct Special; + + impl Buf for Special { + fn remaining(&self) -> usize { + unreachable!("remaining"); + } + + fn bytes(&self) -> &[u8] { + unreachable!("bytes"); + } + + fn advance(&mut self, _: usize) { + unreachable!("advance"); + } + + fn get_u8(&mut self) -> u8 { + // specialized! + b'x' + } + } + + // these should all use the specialized method + assert_eq!(Special.get_u8(), b'x'); + assert_eq!((&mut Special as &mut dyn Buf).get_u8(), b'x'); + assert_eq!((Box::new(Special) as Box).get_u8(), b'x'); + assert_eq!(Box::new(Special).get_u8(), b'x'); +} diff --git a/src/rust/vendor/bytes/tests/test_buf_mut.rs b/src/rust/vendor/bytes/tests/test_buf_mut.rs new file mode 100644 index 000000000..c70e20928 --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_buf_mut.rs @@ -0,0 +1,120 @@ +#![deny(warnings, rust_2018_idioms)] + +#[cfg(feature = "std")] +use bytes::buf::IoSliceMut; +use bytes::{BufMut, BytesMut}; +use core::fmt::Write; +use core::usize; + +#[test] +fn test_vec_as_mut_buf() { + let mut buf = Vec::with_capacity(64); + + assert_eq!(buf.remaining_mut(), usize::MAX); + + assert!(buf.bytes_mut().len() >= 64); + + buf.put(&b"zomg"[..]); + + assert_eq!(&buf, b"zomg"); + + assert_eq!(buf.remaining_mut(), usize::MAX - 4); + assert_eq!(buf.capacity(), 64); + + for _ in 0..16 { + buf.put(&b"zomg"[..]); + } + + assert_eq!(buf.len(), 68); +} + +#[test] +fn test_put_u8() { + let mut buf = Vec::with_capacity(8); + buf.put_u8(33); + assert_eq!(b"\x21", &buf[..]); +} + +#[test] +fn test_put_u16() { + let mut buf = Vec::with_capacity(8); + buf.put_u16(8532); + assert_eq!(b"\x21\x54", &buf[..]); + + buf.clear(); + buf.put_u16_le(8532); + assert_eq!(b"\x54\x21", &buf[..]); +} + +#[test] +#[should_panic(expected = "cannot advance")] +fn test_vec_advance_mut() { + // Verify fix for #354 + let mut buf = Vec::with_capacity(8); + unsafe { + buf.advance_mut(12); + } +} + +#[test] +fn test_clone() { + let mut buf = BytesMut::with_capacity(100); + buf.write_str("this is a test").unwrap(); + let buf2 = buf.clone(); + + buf.write_str(" of our emergency broadcast system").unwrap(); + assert!(buf != buf2); +} + +#[cfg(feature = "std")] +#[test] +fn test_bufs_vec_mut() { + let b1: &mut [u8] = &mut []; + let b2: &mut [u8] = &mut []; + let mut dst = [IoSliceMut::from(b1), IoSliceMut::from(b2)]; + + // with no capacity + let mut buf = BytesMut::new(); + assert_eq!(buf.capacity(), 0); + assert_eq!(1, buf.bytes_vectored_mut(&mut dst[..])); + + // with capacity + let mut buf = BytesMut::with_capacity(64); + assert_eq!(1, buf.bytes_vectored_mut(&mut dst[..])); +} + +#[test] +fn test_mut_slice() { + let mut v = vec![0, 0, 0, 0]; + let mut s = &mut v[..]; + s.put_u32(42); +} + +#[test] +fn test_deref_bufmut_forwards() { + struct Special; + + impl BufMut for Special { + fn remaining_mut(&self) -> usize { + unreachable!("remaining_mut"); + } + + fn bytes_mut(&mut self) -> &mut [std::mem::MaybeUninit] { + unreachable!("bytes_mut"); + } + + unsafe fn advance_mut(&mut self, _: usize) { + unreachable!("advance"); + } + + fn put_u8(&mut self, _: u8) { + // specialized! + } + } + + // these should all use the specialized method + Special.put_u8(b'x'); + (&mut Special as &mut dyn BufMut).put_u8(b'x'); + (Box::new(Special) as Box).put_u8(b'x'); + Box::new(Special).put_u8(b'x'); +} diff --git a/src/rust/vendor/bytes/tests/test_bytes.rs b/src/rust/vendor/bytes/tests/test_bytes.rs new file mode 100644 index 000000000..106fa6f4f --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_bytes.rs @@ -0,0 +1,946 @@ +#![deny(warnings, rust_2018_idioms)] + +use bytes::{Buf, BufMut, Bytes, BytesMut}; + +use std::usize; + +const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb"; +const SHORT: &'static [u8] = b"hello world"; + +fn is_sync() {} +fn is_send() {} + +#[test] +fn test_bounds() { + is_sync::(); + is_sync::(); + is_send::(); + is_send::(); +} + +#[test] +fn test_layout() { + use std::mem; + + assert_eq!( + mem::size_of::(), + mem::size_of::() * 4, + "Bytes size should be 4 words", + ); + assert_eq!( + mem::size_of::(), + mem::size_of::() * 4, + "BytesMut should be 4 words", + ); + + assert_eq!( + mem::size_of::(), + mem::size_of::>(), + "Bytes should be same size as Option", + ); + + assert_eq!( + mem::size_of::(), + mem::size_of::>(), + "BytesMut should be same size as Option", + ); +} + +#[test] +fn from_slice() { + let a = Bytes::from(&b"abcdefgh"[..]); + assert_eq!(a, b"abcdefgh"[..]); + assert_eq!(a, &b"abcdefgh"[..]); + assert_eq!(a, Vec::from(&b"abcdefgh"[..])); + assert_eq!(b"abcdefgh"[..], a); + assert_eq!(&b"abcdefgh"[..], a); + assert_eq!(Vec::from(&b"abcdefgh"[..]), a); + + let a = BytesMut::from(&b"abcdefgh"[..]); + assert_eq!(a, b"abcdefgh"[..]); + assert_eq!(a, &b"abcdefgh"[..]); + assert_eq!(a, Vec::from(&b"abcdefgh"[..])); + assert_eq!(b"abcdefgh"[..], a); + assert_eq!(&b"abcdefgh"[..], a); + assert_eq!(Vec::from(&b"abcdefgh"[..]), a); +} + +#[test] +fn fmt() { + let a = format!("{:?}", Bytes::from(&b"abcdefg"[..])); + let b = "b\"abcdefg\""; + + assert_eq!(a, b); + + let a = format!("{:?}", BytesMut::from(&b"abcdefg"[..])); + assert_eq!(a, b); +} + +#[test] +fn fmt_write() { + use std::fmt::Write; + use std::iter::FromIterator; + let s = String::from_iter((0..10).map(|_| "abcdefg")); + + let mut a = BytesMut::with_capacity(64); + write!(a, "{}", &s[..64]).unwrap(); + assert_eq!(a, s[..64].as_bytes()); + + let mut b = BytesMut::with_capacity(64); + write!(b, "{}", &s[..32]).unwrap(); + write!(b, "{}", &s[32..64]).unwrap(); + assert_eq!(b, s[..64].as_bytes()); + + let mut c = BytesMut::with_capacity(64); + write!(c, "{}", s).unwrap(); + assert_eq!(c, s[..].as_bytes()); +} + +#[test] +fn len() { + let a = Bytes::from(&b"abcdefg"[..]); + assert_eq!(a.len(), 7); + + let a = BytesMut::from(&b"abcdefg"[..]); + assert_eq!(a.len(), 7); + + let a = Bytes::from(&b""[..]); + assert!(a.is_empty()); + + let a = BytesMut::from(&b""[..]); + assert!(a.is_empty()); +} + +#[test] +fn index() { + let a = Bytes::from(&b"hello world"[..]); + assert_eq!(a[0..5], *b"hello"); +} + +#[test] +fn slice() { + let a = Bytes::from(&b"hello world"[..]); + + let b = a.slice(3..5); + assert_eq!(b, b"lo"[..]); + + let b = a.slice(0..0); + assert_eq!(b, b""[..]); + + let b = a.slice(3..3); + assert_eq!(b, b""[..]); + + let b = a.slice(a.len()..a.len()); + assert_eq!(b, b""[..]); + + let b = a.slice(..5); + assert_eq!(b, b"hello"[..]); + + let b = a.slice(3..); + assert_eq!(b, b"lo world"[..]); +} + +#[test] +#[should_panic] +fn slice_oob_1() { + let a = Bytes::from(&b"hello world"[..]); + a.slice(5..44); +} + +#[test] +#[should_panic] +fn slice_oob_2() { + let a = Bytes::from(&b"hello world"[..]); + a.slice(44..49); +} + +#[test] +fn split_off() { + let mut hello = Bytes::from(&b"helloworld"[..]); + let world = hello.split_off(5); + + assert_eq!(hello, &b"hello"[..]); + assert_eq!(world, &b"world"[..]); + + let mut hello = BytesMut::from(&b"helloworld"[..]); + let world = hello.split_off(5); + + assert_eq!(hello, &b"hello"[..]); + assert_eq!(world, &b"world"[..]); +} + +#[test] +#[should_panic] +fn split_off_oob() { + let mut hello = Bytes::from(&b"helloworld"[..]); + let _ = hello.split_off(44); +} + +#[test] +fn split_off_uninitialized() { + let mut bytes = BytesMut::with_capacity(1024); + let other = bytes.split_off(128); + + assert_eq!(bytes.len(), 0); + assert_eq!(bytes.capacity(), 128); + + assert_eq!(other.len(), 0); + assert_eq!(other.capacity(), 896); +} + +#[test] +fn split_off_to_loop() { + let s = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + for i in 0..(s.len() + 1) { + { + let mut bytes = Bytes::from(&s[..]); + let off = bytes.split_off(i); + assert_eq!(i, bytes.len()); + let mut sum = Vec::new(); + sum.extend(bytes.iter()); + sum.extend(off.iter()); + assert_eq!(&s[..], &sum[..]); + } + { + let mut bytes = BytesMut::from(&s[..]); + let off = bytes.split_off(i); + assert_eq!(i, bytes.len()); + let mut sum = Vec::new(); + sum.extend(&bytes); + sum.extend(&off); + assert_eq!(&s[..], &sum[..]); + } + { + let mut bytes = Bytes::from(&s[..]); + let off = bytes.split_to(i); + assert_eq!(i, off.len()); + let mut sum = Vec::new(); + sum.extend(off.iter()); + sum.extend(bytes.iter()); + assert_eq!(&s[..], &sum[..]); + } + { + let mut bytes = BytesMut::from(&s[..]); + let off = bytes.split_to(i); + assert_eq!(i, off.len()); + let mut sum = Vec::new(); + sum.extend(&off); + sum.extend(&bytes); + assert_eq!(&s[..], &sum[..]); + } + } +} + +#[test] +fn split_to_1() { + // Static + let mut a = Bytes::from_static(SHORT); + let b = a.split_to(4); + + assert_eq!(SHORT[4..], a); + assert_eq!(SHORT[..4], b); + + // Allocated + let mut a = Bytes::copy_from_slice(LONG); + let b = a.split_to(4); + + assert_eq!(LONG[4..], a); + assert_eq!(LONG[..4], b); + + let mut a = Bytes::copy_from_slice(LONG); + let b = a.split_to(30); + + assert_eq!(LONG[30..], a); + assert_eq!(LONG[..30], b); +} + +#[test] +fn split_to_2() { + let mut a = Bytes::from(LONG); + assert_eq!(LONG, a); + + let b = a.split_to(1); + + assert_eq!(LONG[1..], a); + drop(b); +} + +#[test] +#[should_panic] +fn split_to_oob() { + let mut hello = Bytes::from(&b"helloworld"[..]); + let _ = hello.split_to(33); +} + +#[test] +#[should_panic] +fn split_to_oob_mut() { + let mut hello = BytesMut::from(&b"helloworld"[..]); + let _ = hello.split_to(33); +} + +#[test] +#[should_panic] +fn split_to_uninitialized() { + let mut bytes = BytesMut::with_capacity(1024); + let _other = bytes.split_to(128); +} + +#[test] +fn split_off_to_at_gt_len() { + fn make_bytes() -> Bytes { + let mut bytes = BytesMut::with_capacity(100); + bytes.put_slice(&[10, 20, 30, 40]); + bytes.freeze() + } + + use std::panic; + + let _ = make_bytes().split_to(4); + let _ = make_bytes().split_off(4); + + assert!(panic::catch_unwind(move || { + let _ = make_bytes().split_to(5); + }) + .is_err()); + + assert!(panic::catch_unwind(move || { + let _ = make_bytes().split_off(5); + }) + .is_err()); +} + +#[test] +fn truncate() { + let s = &b"helloworld"[..]; + let mut hello = Bytes::from(s); + hello.truncate(15); + assert_eq!(hello, s); + hello.truncate(10); + assert_eq!(hello, s); + hello.truncate(5); + assert_eq!(hello, "hello"); +} + +#[test] +fn freeze_clone_shared() { + let s = &b"abcdefgh"[..]; + let b = BytesMut::from(s).split().freeze(); + assert_eq!(b, s); + let c = b.clone(); + assert_eq!(c, s); +} + +#[test] +fn freeze_clone_unique() { + let s = &b"abcdefgh"[..]; + let b = BytesMut::from(s).freeze(); + assert_eq!(b, s); + let c = b.clone(); + assert_eq!(c, s); +} + +#[test] +fn freeze_after_advance() { + let s = &b"abcdefgh"[..]; + let mut b = BytesMut::from(s); + b.advance(1); + assert_eq!(b, s[1..]); + let b = b.freeze(); + // Verify fix for #352. Previously, freeze would ignore the start offset + // for BytesMuts in Vec mode. + assert_eq!(b, s[1..]); +} + +#[test] +fn freeze_after_advance_arc() { + let s = &b"abcdefgh"[..]; + let mut b = BytesMut::from(s); + // Make b Arc + let _ = b.split_to(0); + b.advance(1); + assert_eq!(b, s[1..]); + let b = b.freeze(); + assert_eq!(b, s[1..]); +} + +#[test] +fn freeze_after_split_to() { + let s = &b"abcdefgh"[..]; + let mut b = BytesMut::from(s); + let _ = b.split_to(1); + assert_eq!(b, s[1..]); + let b = b.freeze(); + assert_eq!(b, s[1..]); +} + +#[test] +fn freeze_after_truncate() { + let s = &b"abcdefgh"[..]; + let mut b = BytesMut::from(s); + b.truncate(7); + assert_eq!(b, s[..7]); + let b = b.freeze(); + assert_eq!(b, s[..7]); +} + +#[test] +fn freeze_after_truncate_arc() { + let s = &b"abcdefgh"[..]; + let mut b = BytesMut::from(s); + // Make b Arc + let _ = b.split_to(0); + b.truncate(7); + assert_eq!(b, s[..7]); + let b = b.freeze(); + assert_eq!(b, s[..7]); +} + +#[test] +fn freeze_after_split_off() { + let s = &b"abcdefgh"[..]; + let mut b = BytesMut::from(s); + let _ = b.split_off(7); + assert_eq!(b, s[..7]); + let b = b.freeze(); + assert_eq!(b, s[..7]); +} + +#[test] +fn fns_defined_for_bytes_mut() { + let mut bytes = BytesMut::from(&b"hello world"[..]); + + bytes.as_ptr(); + bytes.as_mut_ptr(); + + // Iterator + let v: Vec = bytes.as_ref().iter().cloned().collect(); + assert_eq!(&v[..], bytes); +} + +#[test] +fn reserve_convert() { + // Vec -> Vec + let mut bytes = BytesMut::from(LONG); + bytes.reserve(64); + assert_eq!(bytes.capacity(), LONG.len() + 64); + + // Arc -> Vec + let mut bytes = BytesMut::from(LONG); + let a = bytes.split_to(30); + + bytes.reserve(128); + assert!(bytes.capacity() >= bytes.len() + 128); + + drop(a); +} + +#[test] +fn reserve_growth() { + let mut bytes = BytesMut::with_capacity(64); + bytes.put("hello world".as_bytes()); + let _ = bytes.split(); + + bytes.reserve(65); + assert_eq!(bytes.capacity(), 128); +} + +#[test] +fn reserve_allocates_at_least_original_capacity() { + let mut bytes = BytesMut::with_capacity(1024); + + for i in 0..1020 { + bytes.put_u8(i as u8); + } + + let _other = bytes.split(); + + bytes.reserve(16); + assert_eq!(bytes.capacity(), 1024); +} + +#[test] +fn reserve_max_original_capacity_value() { + const SIZE: usize = 128 * 1024; + + let mut bytes = BytesMut::with_capacity(SIZE); + + for _ in 0..SIZE { + bytes.put_u8(0u8); + } + + let _other = bytes.split(); + + bytes.reserve(16); + assert_eq!(bytes.capacity(), 64 * 1024); +} + +#[test] +fn reserve_vec_recycling() { + let mut bytes = BytesMut::with_capacity(16); + assert_eq!(bytes.capacity(), 16); + let addr = bytes.as_ptr() as usize; + bytes.put("0123456789012345".as_bytes()); + assert_eq!(bytes.as_ptr() as usize, addr); + bytes.advance(10); + assert_eq!(bytes.capacity(), 6); + bytes.reserve(8); + assert_eq!(bytes.capacity(), 16); + assert_eq!(bytes.as_ptr() as usize, addr); +} + +#[test] +fn reserve_in_arc_unique_does_not_overallocate() { + let mut bytes = BytesMut::with_capacity(1000); + let _ = bytes.split(); + + // now bytes is Arc and refcount == 1 + + assert_eq!(1000, bytes.capacity()); + bytes.reserve(2001); + assert_eq!(2001, bytes.capacity()); +} + +#[test] +fn reserve_in_arc_unique_doubles() { + let mut bytes = BytesMut::with_capacity(1000); + let _ = bytes.split(); + + // now bytes is Arc and refcount == 1 + + assert_eq!(1000, bytes.capacity()); + bytes.reserve(1001); + assert_eq!(2000, bytes.capacity()); +} + +#[test] +fn reserve_in_arc_nonunique_does_not_overallocate() { + let mut bytes = BytesMut::with_capacity(1000); + let _copy = bytes.split(); + + // now bytes is Arc and refcount == 2 + + assert_eq!(1000, bytes.capacity()); + bytes.reserve(2001); + assert_eq!(2001, bytes.capacity()); +} + +#[test] +fn extend_mut() { + let mut bytes = BytesMut::with_capacity(0); + bytes.extend(LONG); + assert_eq!(*bytes, LONG[..]); +} + +#[test] +fn extend_from_slice_mut() { + for &i in &[3, 34] { + let mut bytes = BytesMut::new(); + bytes.extend_from_slice(&LONG[..i]); + bytes.extend_from_slice(&LONG[i..]); + assert_eq!(LONG[..], *bytes); + } +} + +#[test] +fn extend_mut_without_size_hint() { + let mut bytes = BytesMut::with_capacity(0); + let mut long_iter = LONG.iter(); + + // Use iter::from_fn since it doesn't know a size_hint + bytes.extend(std::iter::from_fn(|| long_iter.next())); + assert_eq!(*bytes, LONG[..]); +} + +#[test] +fn from_static() { + let mut a = Bytes::from_static(b"ab"); + let b = a.split_off(1); + + assert_eq!(a, b"a"[..]); + assert_eq!(b, b"b"[..]); +} + +#[test] +fn advance_static() { + let mut a = Bytes::from_static(b"hello world"); + a.advance(6); + assert_eq!(a, &b"world"[..]); +} + +#[test] +fn advance_vec() { + let mut a = Bytes::from(b"hello world boooo yah world zomg wat wat".to_vec()); + a.advance(16); + assert_eq!(a, b"o yah world zomg wat wat"[..]); + + a.advance(4); + assert_eq!(a, b"h world zomg wat wat"[..]); + + a.advance(6); + assert_eq!(a, b"d zomg wat wat"[..]); +} + +#[test] +fn advance_bytes_mut() { + let mut a = BytesMut::from("hello world boooo yah world zomg wat wat"); + a.advance(16); + assert_eq!(a, b"o yah world zomg wat wat"[..]); + + a.advance(4); + assert_eq!(a, b"h world zomg wat wat"[..]); + + // Reserve some space. + a.reserve(1024); + assert_eq!(a, b"h world zomg wat wat"[..]); + + a.advance(6); + assert_eq!(a, b"d zomg wat wat"[..]); +} + +#[test] +#[should_panic] +fn advance_past_len() { + let mut a = BytesMut::from("hello world"); + a.advance(20); +} + +#[test] +// Only run these tests on little endian systems. CI uses qemu for testing +// little endian... and qemu doesn't really support threading all that well. +#[cfg(target_endian = "little")] +fn stress() { + // Tests promoting a buffer from a vec -> shared in a concurrent situation + use std::sync::{Arc, Barrier}; + use std::thread; + + const THREADS: usize = 8; + const ITERS: usize = 1_000; + + for i in 0..ITERS { + let data = [i as u8; 256]; + let buf = Arc::new(Bytes::copy_from_slice(&data[..])); + + let barrier = Arc::new(Barrier::new(THREADS)); + let mut joins = Vec::with_capacity(THREADS); + + for _ in 0..THREADS { + let c = barrier.clone(); + let buf = buf.clone(); + + joins.push(thread::spawn(move || { + c.wait(); + let buf: Bytes = (*buf).clone(); + drop(buf); + })); + } + + for th in joins { + th.join().unwrap(); + } + + assert_eq!(*buf, data[..]); + } +} + +#[test] +fn partial_eq_bytesmut() { + let bytes = Bytes::from(&b"The quick red fox"[..]); + let bytesmut = BytesMut::from(&b"The quick red fox"[..]); + assert!(bytes == bytesmut); + assert!(bytesmut == bytes); + let bytes2 = Bytes::from(&b"Jumped over the lazy brown dog"[..]); + assert!(bytes2 != bytesmut); + assert!(bytesmut != bytes2); +} + +/* +#[test] +fn bytes_unsplit_basic() { + let buf = Bytes::from(&b"aaabbbcccddd"[..]); + + let splitted = buf.split_off(6); + assert_eq!(b"aaabbb", &buf[..]); + assert_eq!(b"cccddd", &splitted[..]); + + buf.unsplit(splitted); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_empty_other() { + let buf = Bytes::from(&b"aaabbbcccddd"[..]); + + // empty other + let other = Bytes::new(); + + buf.unsplit(other); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_empty_self() { + // empty self + let mut buf = Bytes::new(); + + let mut other = Bytes::with_capacity(64); + other.extend_from_slice(b"aaabbbcccddd"); + + buf.unsplit(other); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_arc_different() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeee"); + + buf.split_off(8); //arc + + let mut buf2 = Bytes::with_capacity(64); + buf2.extend_from_slice(b"ccccddddeeee"); + + buf2.split_off(8); //arc + + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_arc_non_contiguous() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeeeccccdddd"); + + let mut buf2 = buf.split_off(8); //arc + + let buf3 = buf2.split_off(4); //arc + + buf.unsplit(buf3); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_two_split_offs() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbccccdddd"); + + let mut buf2 = buf.split_off(8); //arc + let buf3 = buf2.split_off(4); //arc + + buf2.unsplit(buf3); + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn bytes_unsplit_overlapping_references() { + let mut buf = Bytes::with_capacity(64); + buf.extend_from_slice(b"abcdefghijklmnopqrstuvwxyz"); + let mut buf0010 = buf.slice(0..10); + let buf1020 = buf.slice(10..20); + let buf0515 = buf.slice(5..15); + buf0010.unsplit(buf1020); + assert_eq!(b"abcdefghijklmnopqrst", &buf0010[..]); + assert_eq!(b"fghijklmno", &buf0515[..]); +} +*/ + +#[test] +fn bytes_mut_unsplit_basic() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaabbbcccddd"); + + let splitted = buf.split_off(6); + assert_eq!(b"aaabbb", &buf[..]); + assert_eq!(b"cccddd", &splitted[..]); + + buf.unsplit(splitted); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn bytes_mut_unsplit_empty_other() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaabbbcccddd"); + + // empty other + let other = BytesMut::new(); + + buf.unsplit(other); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn bytes_mut_unsplit_empty_self() { + // empty self + let mut buf = BytesMut::new(); + + let mut other = BytesMut::with_capacity(64); + other.extend_from_slice(b"aaabbbcccddd"); + + buf.unsplit(other); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn bytes_mut_unsplit_arc_different() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeee"); + + let _ = buf.split_off(8); //arc + + let mut buf2 = BytesMut::with_capacity(64); + buf2.extend_from_slice(b"ccccddddeeee"); + + let _ = buf2.split_off(8); //arc + + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn bytes_mut_unsplit_arc_non_contiguous() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeeeccccdddd"); + + let mut buf2 = buf.split_off(8); //arc + + let buf3 = buf2.split_off(4); //arc + + buf.unsplit(buf3); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn bytes_mut_unsplit_two_split_offs() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbccccdddd"); + + let mut buf2 = buf.split_off(8); //arc + let buf3 = buf2.split_off(4); //arc + + buf2.unsplit(buf3); + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn from_iter_no_size_hint() { + use std::iter; + + let mut expect = vec![]; + + let actual: Bytes = iter::repeat(b'x') + .scan(100, |cnt, item| { + if *cnt >= 1 { + *cnt -= 1; + expect.push(item); + Some(item) + } else { + None + } + }) + .collect(); + + assert_eq!(&actual[..], &expect[..]); +} + +fn test_slice_ref(bytes: &Bytes, start: usize, end: usize, expected: &[u8]) { + let slice = &(bytes.as_ref()[start..end]); + let sub = bytes.slice_ref(&slice); + assert_eq!(&sub[..], expected); +} + +#[test] +fn slice_ref_works() { + let bytes = Bytes::from(&b"012345678"[..]); + + test_slice_ref(&bytes, 0, 0, b""); + test_slice_ref(&bytes, 0, 3, b"012"); + test_slice_ref(&bytes, 2, 6, b"2345"); + test_slice_ref(&bytes, 7, 9, b"78"); + test_slice_ref(&bytes, 9, 9, b""); +} + +#[test] +fn slice_ref_empty() { + let bytes = Bytes::from(&b""[..]); + let slice = &(bytes.as_ref()[0..0]); + + let sub = bytes.slice_ref(&slice); + assert_eq!(&sub[..], b""); +} + +#[test] +fn slice_ref_empty_subslice() { + let bytes = Bytes::from(&b"abcde"[..]); + let subbytes = bytes.slice(0..0); + let slice = &subbytes[..]; + // The `slice` object is derived from the original `bytes` object + // so `slice_ref` should work. + assert_eq!(Bytes::new(), bytes.slice_ref(slice)); +} + +#[test] +#[should_panic] +fn slice_ref_catches_not_a_subset() { + let bytes = Bytes::from(&b"012345678"[..]); + let slice = &b"012345"[0..4]; + + bytes.slice_ref(slice); +} + +#[test] +fn slice_ref_not_an_empty_subset() { + let bytes = Bytes::from(&b"012345678"[..]); + let slice = &b""[0..0]; + + assert_eq!(Bytes::new(), bytes.slice_ref(slice)); +} + +#[test] +fn empty_slice_ref_not_an_empty_subset() { + let bytes = Bytes::new(); + let slice = &b"some other slice"[0..0]; + + assert_eq!(Bytes::new(), bytes.slice_ref(slice)); +} + +#[test] +fn bytes_buf_mut_advance() { + let mut bytes = BytesMut::with_capacity(1024); + + unsafe { + let ptr = bytes.bytes_mut().as_ptr(); + assert_eq!(1024, bytes.bytes_mut().len()); + + bytes.advance_mut(10); + + let next = bytes.bytes_mut().as_ptr(); + assert_eq!(1024 - 10, bytes.bytes_mut().len()); + assert_eq!(ptr.offset(10), next); + + // advance to the end + bytes.advance_mut(1024 - 10); + + // The buffer size is doubled + assert_eq!(1024, bytes.bytes_mut().len()); + } +} + +#[test] +#[should_panic] +fn bytes_reserve_overflow() { + let mut bytes = BytesMut::with_capacity(1024); + bytes.put_slice(b"hello world"); + + bytes.reserve(usize::MAX); +} + +#[test] +fn bytes_with_capacity_but_empty() { + // See https://github.com/tokio-rs/bytes/issues/340 + let vec = Vec::with_capacity(1); + let _ = Bytes::from(vec); +} diff --git a/src/rust/vendor/bytes/tests/test_bytes_odd_alloc.rs b/src/rust/vendor/bytes/tests/test_bytes_odd_alloc.rs new file mode 100644 index 000000000..4ce424b7c --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_bytes_odd_alloc.rs @@ -0,0 +1,67 @@ +//! Test using `Bytes` with an allocator that hands out "odd" pointers for +//! vectors (pointers where the LSB is set). + +use std::alloc::{GlobalAlloc, Layout, System}; +use std::ptr; + +use bytes::Bytes; + +#[global_allocator] +static ODD: Odd = Odd; + +struct Odd; + +unsafe impl GlobalAlloc for Odd { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() == 1 && layout.size() > 0 { + // Allocate slightly bigger so that we can offset the pointer by 1 + let size = layout.size() + 1; + let new_layout = match Layout::from_size_align(size, 1) { + Ok(layout) => layout, + Err(_err) => return ptr::null_mut(), + }; + let ptr = System.alloc(new_layout); + if !ptr.is_null() { + let ptr = ptr.offset(1); + ptr + } else { + ptr + } + } else { + System.alloc(layout) + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + if layout.align() == 1 && layout.size() > 0 { + let size = layout.size() + 1; + let new_layout = match Layout::from_size_align(size, 1) { + Ok(layout) => layout, + Err(_err) => std::process::abort(), + }; + System.dealloc(ptr.offset(-1), new_layout); + } else { + System.dealloc(ptr, layout); + } + } +} + +#[test] +fn sanity_check_odd_allocator() { + let vec = vec![33u8; 1024]; + let p = vec.as_ptr() as usize; + assert!(p & 0x1 == 0x1, "{:#b}", p); +} + +#[test] +fn test_bytes_from_vec_drop() { + let vec = vec![33u8; 1024]; + let _b = Bytes::from(vec); +} + +#[test] +fn test_bytes_clone_drop() { + let vec = vec![33u8; 1024]; + let b1 = Bytes::from(vec); + let _b2 = b1.clone(); +} diff --git a/src/rust/vendor/bytes/tests/test_bytes_vec_alloc.rs b/src/rust/vendor/bytes/tests/test_bytes_vec_alloc.rs new file mode 100644 index 000000000..418a9cd64 --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_bytes_vec_alloc.rs @@ -0,0 +1,79 @@ +use std::alloc::{GlobalAlloc, Layout, System}; +use std::{mem, ptr}; + +use bytes::{Buf, Bytes}; + +#[global_allocator] +static LEDGER: Ledger = Ledger; + +struct Ledger; + +const USIZE_SIZE: usize = mem::size_of::(); + +unsafe impl GlobalAlloc for Ledger { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() == 1 && layout.size() > 0 { + // Allocate extra space to stash a record of + // how much space there was. + let orig_size = layout.size(); + let size = orig_size + USIZE_SIZE; + let new_layout = match Layout::from_size_align(size, 1) { + Ok(layout) => layout, + Err(_err) => return ptr::null_mut(), + }; + let ptr = System.alloc(new_layout); + if !ptr.is_null() { + (ptr as *mut usize).write(orig_size); + let ptr = ptr.offset(USIZE_SIZE as isize); + ptr + } else { + ptr + } + } else { + System.alloc(layout) + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + if layout.align() == 1 && layout.size() > 0 { + let off_ptr = (ptr as *mut usize).offset(-1); + let orig_size = off_ptr.read(); + if orig_size != layout.size() { + panic!( + "bad dealloc: alloc size was {}, dealloc size is {}", + orig_size, + layout.size() + ); + } + + let new_layout = match Layout::from_size_align(layout.size() + USIZE_SIZE, 1) { + Ok(layout) => layout, + Err(_err) => std::process::abort(), + }; + System.dealloc(off_ptr as *mut u8, new_layout); + } else { + System.dealloc(ptr, layout); + } + } +} +#[test] +fn test_bytes_advance() { + let mut bytes = Bytes::from(vec![10, 20, 30]); + bytes.advance(1); + drop(bytes); +} + +#[test] +fn test_bytes_truncate() { + let mut bytes = Bytes::from(vec![10, 20, 30]); + bytes.truncate(2); + drop(bytes); +} + +#[test] +fn test_bytes_truncate_and_advance() { + let mut bytes = Bytes::from(vec![10, 20, 30]); + bytes.truncate(2); + bytes.advance(1); + drop(bytes); +} diff --git a/src/rust/vendor/bytes/tests/test_chain.rs b/src/rust/vendor/bytes/tests/test_chain.rs new file mode 100644 index 000000000..82de7fcec --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_chain.rs @@ -0,0 +1,135 @@ +#![deny(warnings, rust_2018_idioms)] + +use bytes::buf::{BufExt, BufMutExt}; +use bytes::{Buf, BufMut, Bytes}; +#[cfg(feature = "std")] +use std::io::IoSlice; + +#[test] +fn collect_two_bufs() { + let a = Bytes::from(&b"hello"[..]); + let b = Bytes::from(&b"world"[..]); + + let res = a.chain(b).to_bytes(); + assert_eq!(res, &b"helloworld"[..]); +} + +#[test] +fn writing_chained() { + let mut a = [0u8; 64]; + let mut b = [0u8; 64]; + + { + let mut buf = (&mut a[..]).chain_mut(&mut b[..]); + + for i in 0u8..128 { + buf.put_u8(i); + } + } + + for i in 0..64 { + let expect = i as u8; + assert_eq!(expect, a[i]); + assert_eq!(expect + 64, b[i]); + } +} + +#[test] +fn iterating_two_bufs() { + let a = Bytes::from(&b"hello"[..]); + let b = Bytes::from(&b"world"[..]); + + let res: Vec = a.chain(b).into_iter().collect(); + assert_eq!(res, &b"helloworld"[..]); +} + +#[cfg(feature = "std")] +#[test] +fn vectored_read() { + let a = Bytes::from(&b"hello"[..]); + let b = Bytes::from(&b"world"[..]); + + let mut buf = a.chain(b); + + { + let b1: &[u8] = &mut []; + let b2: &[u8] = &mut []; + let b3: &[u8] = &mut []; + let b4: &[u8] = &mut []; + let mut iovecs = [ + IoSlice::new(b1), + IoSlice::new(b2), + IoSlice::new(b3), + IoSlice::new(b4), + ]; + + assert_eq!(2, buf.bytes_vectored(&mut iovecs)); + assert_eq!(iovecs[0][..], b"hello"[..]); + assert_eq!(iovecs[1][..], b"world"[..]); + assert_eq!(iovecs[2][..], b""[..]); + assert_eq!(iovecs[3][..], b""[..]); + } + + buf.advance(2); + + { + let b1: &[u8] = &mut []; + let b2: &[u8] = &mut []; + let b3: &[u8] = &mut []; + let b4: &[u8] = &mut []; + let mut iovecs = [ + IoSlice::new(b1), + IoSlice::new(b2), + IoSlice::new(b3), + IoSlice::new(b4), + ]; + + assert_eq!(2, buf.bytes_vectored(&mut iovecs)); + assert_eq!(iovecs[0][..], b"llo"[..]); + assert_eq!(iovecs[1][..], b"world"[..]); + assert_eq!(iovecs[2][..], b""[..]); + assert_eq!(iovecs[3][..], b""[..]); + } + + buf.advance(3); + + { + let b1: &[u8] = &mut []; + let b2: &[u8] = &mut []; + let b3: &[u8] = &mut []; + let b4: &[u8] = &mut []; + let mut iovecs = [ + IoSlice::new(b1), + IoSlice::new(b2), + IoSlice::new(b3), + IoSlice::new(b4), + ]; + + assert_eq!(1, buf.bytes_vectored(&mut iovecs)); + assert_eq!(iovecs[0][..], b"world"[..]); + assert_eq!(iovecs[1][..], b""[..]); + assert_eq!(iovecs[2][..], b""[..]); + assert_eq!(iovecs[3][..], b""[..]); + } + + buf.advance(3); + + { + let b1: &[u8] = &mut []; + let b2: &[u8] = &mut []; + let b3: &[u8] = &mut []; + let b4: &[u8] = &mut []; + let mut iovecs = [ + IoSlice::new(b1), + IoSlice::new(b2), + IoSlice::new(b3), + IoSlice::new(b4), + ]; + + assert_eq!(1, buf.bytes_vectored(&mut iovecs)); + assert_eq!(iovecs[0][..], b"ld"[..]); + assert_eq!(iovecs[1][..], b""[..]); + assert_eq!(iovecs[2][..], b""[..]); + assert_eq!(iovecs[3][..], b""[..]); + } +} diff --git a/src/rust/vendor/bytes/tests/test_debug.rs b/src/rust/vendor/bytes/tests/test_debug.rs new file mode 100644 index 000000000..7528bac87 --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_debug.rs @@ -0,0 +1,35 @@ +#![deny(warnings, rust_2018_idioms)] + +use bytes::Bytes; + +#[test] +fn fmt() { + let vec: Vec<_> = (0..0x100).map(|b| b as u8).collect(); + + let expected = "b\"\ + \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\ + \\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\ + \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\ + \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\ + \x20!\\\"#$%&'()*+,-./0123456789:;<=>?\ + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\ + `abcdefghijklmnopqrstuvwxyz{|}~\\x7f\ + \\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\ + \\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\ + \\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\ + \\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\ + \\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\ + \\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\ + \\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\ + \\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\ + \\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\ + \\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\ + \\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\ + \\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\ + \\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\ + \\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\ + \\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\ + \\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\""; + + assert_eq!(expected, format!("{:?}", Bytes::from(vec))); +} diff --git a/src/rust/vendor/bytes/tests/test_iter.rs b/src/rust/vendor/bytes/tests/test_iter.rs new file mode 100644 index 000000000..2302a69d6 --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_iter.rs @@ -0,0 +1,21 @@ +#![deny(warnings, rust_2018_idioms)] + +use bytes::Bytes; + +#[test] +fn iter_len() { + let buf = Bytes::from_static(b"hello world"); + let iter = buf.iter(); + + assert_eq!(iter.size_hint(), (11, Some(11))); + assert_eq!(iter.len(), 11); +} + +#[test] +fn empty_iter_len() { + let buf = Bytes::from_static(b""); + let iter = buf.iter(); + + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.len(), 0); +} diff --git a/src/rust/vendor/bytes/tests/test_reader.rs b/src/rust/vendor/bytes/tests/test_reader.rs new file mode 100644 index 000000000..b5da2c963 --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_reader.rs @@ -0,0 +1,29 @@ +#![deny(warnings, rust_2018_idioms)] +#![cfg(feature = "std")] + +use std::io::{BufRead, Read}; + +use bytes::buf::BufExt; + +#[test] +fn read() { + let buf1 = &b"hello "[..]; + let buf2 = &b"world"[..]; + let buf = BufExt::chain(buf1, buf2); // Disambiguate with Read::chain + let mut buffer = Vec::new(); + buf.reader().read_to_end(&mut buffer).unwrap(); + assert_eq!(b"hello world", &buffer[..]); +} + +#[test] +fn buf_read() { + let buf1 = &b"hell"[..]; + let buf2 = &b"o\nworld"[..]; + let mut reader = BufExt::chain(buf1, buf2).reader(); + let mut line = String::new(); + reader.read_line(&mut line).unwrap(); + assert_eq!("hello\n", &line); + line.clear(); + reader.read_line(&mut line).unwrap(); + assert_eq!("world", &line); +} diff --git a/src/rust/vendor/bytes/tests/test_serde.rs b/src/rust/vendor/bytes/tests/test_serde.rs new file mode 100644 index 000000000..36b87f28e --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_serde.rs @@ -0,0 +1,20 @@ +#![cfg(feature = "serde")] +#![deny(warnings, rust_2018_idioms)] + +use serde_test::{assert_tokens, Token}; + +#[test] +fn test_ser_de_empty() { + let b = bytes::Bytes::new(); + assert_tokens(&b, &[Token::Bytes(b"")]); + let b = bytes::BytesMut::with_capacity(0); + assert_tokens(&b, &[Token::Bytes(b"")]); +} + +#[test] +fn test_ser_de() { + let b = bytes::Bytes::from(&b"bytes"[..]); + assert_tokens(&b, &[Token::Bytes(b"bytes")]); + let b = bytes::BytesMut::from(&b"bytes"[..]); + assert_tokens(&b, &[Token::Bytes(b"bytes")]); +} diff --git a/src/rust/vendor/bytes/tests/test_take.rs b/src/rust/vendor/bytes/tests/test_take.rs new file mode 100644 index 000000000..b9b525b1f --- /dev/null +++ b/src/rust/vendor/bytes/tests/test_take.rs @@ -0,0 +1,12 @@ +#![deny(warnings, rust_2018_idioms)] + +use bytes::buf::{Buf, BufExt}; + +#[test] +fn long_take() { + // Tests that get a take with a size greater than the buffer length will not + // overrun the buffer. Regression test for #138. + let buf = b"hello world".take(100); + assert_eq!(11, buf.remaining()); + assert_eq!(b"hello world", buf.bytes()); +} diff --git a/src/rust/vendor/either/.cargo-checksum.json b/src/rust/vendor/either/.cargo-checksum.json new file mode 100644 index 000000000..bbcdeb482 --- /dev/null +++ b/src/rust/vendor/either/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"f64e4d72e7ea46794a911a98b24d3107b00339092792b3e6d5bbaaa0e532a2e5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README-crates.io.md":"b775991a01ab4a0a8de6169f597775319d9ce8178f5c74ccdc634f13a286b20c","README.rst":"9c5d8e56338eb20f51b00db4467edadf5ea733da0365131dd39b3ad6a4c1412d","src/lib.rs":"40b9850fd27674a0f8931d5d6b1f226ec2f0119d6ecd2462a24287df40430fa4"},"package":"bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"} \ No newline at end of file diff --git a/src/rust/vendor/either/Cargo.toml b/src/rust/vendor/either/Cargo.toml new file mode 100644 index 000000000..a4cd0f76c --- /dev/null +++ b/src/rust/vendor/either/Cargo.toml @@ -0,0 +1,37 @@ +# 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] +name = "either" +version = "1.5.3" +authors = ["bluss"] +description = "The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases.\n" +documentation = "https://docs.rs/either/1/" +readme = "README-crates.io.md" +keywords = ["data-structure", "no_std"] +categories = ["data-structures", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/bluss/either" +[package.metadata.docs.rs] +features = ["serde"] + +[package.metadata.release] +no-dev-version = true +tag-name = "{{version}}" +[dependencies.serde] +version = "1.0" +features = ["derive"] +optional = true + +[features] +default = ["use_std"] +use_std = [] diff --git a/src/rust/vendor/either/LICENSE-APACHE b/src/rust/vendor/either/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/either/LICENSE-APACHE @@ -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. diff --git a/src/rust/vendor/either/LICENSE-MIT b/src/rust/vendor/either/LICENSE-MIT new file mode 100644 index 000000000..9203baa05 --- /dev/null +++ b/src/rust/vendor/either/LICENSE-MIT @@ -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. diff --git a/src/rust/vendor/either/README-crates.io.md b/src/rust/vendor/either/README-crates.io.md new file mode 100644 index 000000000..d36890278 --- /dev/null +++ b/src/rust/vendor/either/README-crates.io.md @@ -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`. diff --git a/src/rust/vendor/either/README.rst b/src/rust/vendor/either/README.rst new file mode 100644 index 000000000..573888476 --- /dev/null +++ b/src/rust/vendor/either/README.rst @@ -0,0 +1,119 @@ + +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://travis-ci.org/bluss/either.svg?branch=master +.. _build_status: https://travis-ci.org/bluss/either + +.. |crates| image:: http://meritbadge.herokuapp.com/either +.. _crates: https://crates.io/crates/either + +How to use with cargo:: + + [dependencies] + either = "1.5" + + +Recent Changes +-------------- + +- 1.5.3 + + - Add new method ``.map()`` for ``Either`` 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`` 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 +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. diff --git a/src/rust/vendor/either/src/lib.rs b/src/rust/vendor/either/src/lib.rs new file mode 100644 index 000000000..1ba5ed747 --- /dev/null +++ b/src/rust/vendor/either/src/lib.rs @@ -0,0 +1,974 @@ +//! The enum [`Either`] with variants `Left` and `Right` is a general purpose +//! sum type with two cases. +//! +//! [`Either`]: enum.Either.html +//! +//! **Crate features:** +//! +//! * `"use_std"` +//! Enabled by default. Disable to make the library `#![no_std]`. +//! +//! * `"serde"` +//! Disabled by default. Enable to `#[derive(Serialize, Deserialize)]` for `Either` +//! + +#![doc(html_root_url = "https://docs.rs/either/1/")] +#![cfg_attr(all(not(test), not(feature = "use_std")), no_std)] +#[cfg(all(not(test), not(feature = "use_std")))] +extern crate core as std; + +#[cfg(feature = "serde")] +#[macro_use] +extern crate serde; + +use std::convert::{AsRef, AsMut}; +use std::fmt; +use std::iter; +use std::ops::Deref; +use std::ops::DerefMut; +#[cfg(any(test, feature = "use_std"))] +use std::io::{self, Write, Read, BufRead}; +#[cfg(any(test, feature = "use_std"))] +use std::error::Error; + +pub use Either::{Left, Right}; + +/// The enum `Either` with variants `Left` and `Right` is a general purpose +/// sum type with two cases. +/// +/// The `Either` type is symmetric and treats its variants the same way, without +/// preference. +/// (For representing success or error, use the regular `Result` enum instead.) +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Either { + /// A value of type `L`. + Left(L), + /// A value of type `R`. + Right(R), +} + +macro_rules! either { + ($value:expr, $pattern:pat => $result:expr) => ( + match $value { + Either::Left($pattern) => $result, + Either::Right($pattern) => $result, + } + ) +} + +/// Macro for unwrapping the left side of an `Either`, which fails early +/// with the opposite side. Can only be used in functions that return +/// `Either` because of the early return of `Right` that it provides. +/// +/// See also `try_right!` for its dual, which applies the same just to the +/// right side. +/// +/// # Example +/// +/// ``` +/// #[macro_use] extern crate either; +/// use either::{Either, Left, Right}; +/// +/// fn twice(wrapper: Either) -> Either { +/// let value = try_left!(wrapper); +/// Left(value * 2) +/// } +/// +/// fn main() { +/// assert_eq!(twice(Left(2)), Left(4)); +/// assert_eq!(twice(Right("ups")), Right("ups")); +/// } +/// ``` +#[macro_export] +macro_rules! try_left { + ($expr:expr) => ( + match $expr { + $crate::Left(val) => val, + $crate::Right(err) => return $crate::Right(::std::convert::From::from(err)) + } + ) +} + +/// Dual to `try_left!`, see its documentation for more information. +#[macro_export] +macro_rules! try_right { + ($expr:expr) => ( + match $expr { + $crate::Left(err) => return $crate::Left(::std::convert::From::from(err)), + $crate::Right(val) => val + } + ) +} + +impl Either { + /// Return true if the value is the `Left` variant. + /// + /// ``` + /// use either::*; + /// + /// let values = [Left(1), Right("the right value")]; + /// assert_eq!(values[0].is_left(), true); + /// assert_eq!(values[1].is_left(), false); + /// ``` + pub fn is_left(&self) -> bool { + match *self { + Left(_) => true, + Right(_) => false, + } + } + + /// Return true if the value is the `Right` variant. + /// + /// ``` + /// use either::*; + /// + /// let values = [Left(1), Right("the right value")]; + /// assert_eq!(values[0].is_right(), false); + /// assert_eq!(values[1].is_right(), true); + /// ``` + pub fn is_right(&self) -> bool { + !self.is_left() + } + + /// Convert the left side of `Either` to an `Option`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, ()> = Left("some value"); + /// assert_eq!(left.left(), Some("some value")); + /// + /// let right: Either<(), _> = Right(321); + /// assert_eq!(right.left(), None); + /// ``` + pub fn left(self) -> Option { + match self { + Left(l) => Some(l), + Right(_) => None, + } + } + + /// Convert the right side of `Either` to an `Option`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, ()> = Left("some value"); + /// assert_eq!(left.right(), None); + /// + /// let right: Either<(), _> = Right(321); + /// assert_eq!(right.right(), Some(321)); + /// ``` + pub fn right(self) -> Option { + match self { + Left(_) => None, + Right(r) => Some(r), + } + } + + /// Convert `&Either` to `Either<&L, &R>`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, ()> = Left("some value"); + /// assert_eq!(left.as_ref(), Left(&"some value")); + /// + /// let right: Either<(), _> = Right("some value"); + /// assert_eq!(right.as_ref(), Right(&"some value")); + /// ``` + pub fn as_ref(&self) -> Either<&L, &R> { + match *self { + Left(ref inner) => Left(inner), + Right(ref inner) => Right(inner), + } + } + + /// Convert `&mut Either` to `Either<&mut L, &mut R>`. + /// + /// ``` + /// use either::*; + /// + /// fn mutate_left(value: &mut Either) { + /// if let Some(l) = value.as_mut().left() { + /// *l = 999; + /// } + /// } + /// + /// let mut left = Left(123); + /// let mut right = Right(123); + /// mutate_left(&mut left); + /// mutate_left(&mut right); + /// assert_eq!(left, Left(999)); + /// assert_eq!(right, Right(123)); + /// ``` + pub fn as_mut(&mut self) -> Either<&mut L, &mut R> { + match *self { + Left(ref mut inner) => Left(inner), + Right(ref mut inner) => Right(inner), + } + } + + /// Convert `Either` to `Either`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, ()> = Left(123); + /// assert_eq!(left.flip(), Right(123)); + /// + /// let right: Either<(), _> = Right("some value"); + /// assert_eq!(right.flip(), Left("some value")); + /// ``` + pub fn flip(self) -> Either { + match self { + Left(l) => Right(l), + Right(r) => Left(r), + } + } + + /// Apply the function `f` on the value in the `Left` variant if it is present rewrapping the + /// result in `Left`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.map_left(|x| x * 2), Left(246)); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.map_left(|x| x * 2), Right(123)); + /// ``` + pub fn map_left(self, f: F) -> Either + where F: FnOnce(L) -> M + { + match self { + Left(l) => Left(f(l)), + Right(r) => Right(r), + } + } + + /// Apply the function `f` on the value in the `Right` variant if it is present rewrapping the + /// result in `Right`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.map_right(|x| x * 2), Left(123)); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.map_right(|x| x * 2), Right(246)); + /// ``` + pub fn map_right(self, f: F) -> Either + where F: FnOnce(R) -> S + { + match self { + Left(l) => Left(l), + Right(r) => Right(f(r)), + } + } + + /// Apply one of two functions depending on contents, unifying their result. If the value is + /// `Left(L)` then the first function `f` is applied; if it is `Right(R)` then the second + /// function `g` is applied. + /// + /// ``` + /// use either::*; + /// + /// fn square(n: u32) -> i32 { (n * n) as i32 } + /// fn negate(n: i32) -> i32 { -n } + /// + /// let left: Either = Left(4); + /// assert_eq!(left.either(square, negate), 16); + /// + /// let right: Either = Right(-4); + /// assert_eq!(right.either(square, negate), 4); + /// ``` + pub fn either(self, f: F, g: G) -> T + where F: FnOnce(L) -> T, + G: FnOnce(R) -> T + { + match self { + Left(l) => f(l), + Right(r) => g(r), + } + } + + /// Like `either`, but provide some context to whichever of the + /// functions ends up being called. + /// + /// ``` + /// // In this example, the context is a mutable reference + /// use either::*; + /// + /// let mut result = Vec::new(); + /// + /// let values = vec![Left(2), Right(2.7)]; + /// + /// for value in values { + /// value.either_with(&mut result, + /// |ctx, integer| ctx.push(integer), + /// |ctx, real| ctx.push(f64::round(real) as i32)); + /// } + /// + /// assert_eq!(result, vec![2, 3]); + /// ``` + pub fn either_with(self, ctx: Ctx, f: F, g: G) -> T + where F: FnOnce(Ctx, L) -> T, + G: FnOnce(Ctx, R) -> T + { + match self { + Left(l) => f(ctx, l), + Right(r) => g(ctx, r), + } + } + + /// Apply the function `f` on the value in the `Left` variant if it is present. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.left_and_then::<_,()>(|x| Right(x * 2)), Right(246)); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.left_and_then(|x| Right::<(), _>(x * 2)), Right(123)); + /// ``` + pub fn left_and_then(self, f: F) -> Either + where F: FnOnce(L) -> Either + { + match self { + Left(l) => f(l), + Right(r) => Right(r), + } + } + + /// Apply the function `f` on the value in the `Right` variant if it is present. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.right_and_then(|x| Right(x * 2)), Left(123)); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.right_and_then(|x| Right(x * 2)), Right(246)); + /// ``` + pub fn right_and_then(self, f: F) -> Either + where F: FnOnce(R) -> Either + { + match self { + Left(l) => Left(l), + Right(r) => f(r), + } + } + + /// Convert the inner value to an iterator. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, Vec> = Left(vec![1, 2, 3, 4, 5]); + /// let mut right: Either, _> = Right(vec![]); + /// right.extend(left.into_iter()); + /// assert_eq!(right, Right(vec![1, 2, 3, 4, 5])); + /// ``` + pub fn into_iter(self) -> Either + where L: IntoIterator, + R: IntoIterator + { + match self { + Left(l) => Left(l.into_iter()), + Right(r) => Right(r.into_iter()), + } + } + + /// Return left value or given value + /// + /// Arguments passed to `left_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use [`left_or_else`], + /// which is lazily evaluated. + /// + /// [`left_or_else`]: #method.left_or_else + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either<&str, &str> = Left("left"); + /// assert_eq!(left.left_or("foo"), "left"); + /// + /// let right: Either<&str, &str> = Right("right"); + /// assert_eq!(right.left_or("left"), "left"); + /// ``` + pub fn left_or(self, other: L) -> L { + match self { + Either::Left(l) => l, + Either::Right(_) => other, + } + } + + /// Return left or a default + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either = Left("left".to_string()); + /// assert_eq!(left.left_or_default(), "left"); + /// + /// let right: Either = Right(42); + /// assert_eq!(right.left_or_default(), String::default()); + /// ``` + pub fn left_or_default(self) -> L + where + L: Default, + { + match self { + Either::Left(l) => l, + Either::Right(_) => L::default(), + } + } + + /// Returns left value or computes it from a closure + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either = Left("3".to_string()); + /// assert_eq!(left.left_or_else(|_| unreachable!()), "3"); + /// + /// let right: Either = Right(3); + /// assert_eq!(right.left_or_else(|x| x.to_string()), "3"); + /// ``` + pub fn left_or_else(self, f: F) -> L + where + F: FnOnce(R) -> L, + { + match self { + Either::Left(l) => l, + Either::Right(r) => f(r), + } + } + + /// Return right value or given value + /// + /// Arguments passed to `right_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use [`right_or_else`], + /// which is lazily evaluated. + /// + /// [`right_or_else`]: #method.right_or_else + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let right: Either<&str, &str> = Right("right"); + /// assert_eq!(right.right_or("foo"), "right"); + /// + /// let left: Either<&str, &str> = Left("left"); + /// assert_eq!(left.right_or("right"), "right"); + /// ``` + pub fn right_or(self, other: R) -> R { + match self { + Either::Left(_) => other, + Either::Right(r) => r, + } + } + + /// Return right or a default + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either = Left("left".to_string()); + /// assert_eq!(left.right_or_default(), u32::default()); + /// + /// let right: Either = Right(42); + /// assert_eq!(right.right_or_default(), 42); + /// ``` + pub fn right_or_default(self) -> R + where + R: Default, + { + match self { + Either::Left(_) => R::default(), + Either::Right(r) => r, + } + } + + /// Returns right value or computes it from a closure + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either = Left("3".to_string()); + /// assert_eq!(left.right_or_else(|x| x.parse().unwrap()), 3); + /// + /// let right: Either = Right(3); + /// assert_eq!(right.right_or_else(|_| unreachable!()), 3); + /// ``` + pub fn right_or_else(self, f: F) -> R + where + F: FnOnce(L) -> R, + { + match self { + Either::Left(l) => f(l), + Either::Right(r) => r, + } + } +} + +impl Either<(T, L), (T, R)> { + /// Factor out a homogeneous type from an either of pairs. + /// + /// Here, the homogeneous type is the first element of the pairs. + /// + /// ``` + /// use either::*; + /// let left: Either<_, (u32, String)> = Left((123, vec![0])); + /// assert_eq!(left.factor_first().0, 123); + /// + /// let right: Either<(u32, Vec), _> = Right((123, String::new())); + /// assert_eq!(right.factor_first().0, 123); + /// ``` + pub fn factor_first(self) -> (T, Either) { + match self { + Left((t, l)) => (t, Left(l)), + Right((t, r)) => (t, Right(r)), + } + } +} + +impl Either<(L, T), (R, T)> { + /// Factor out a homogeneous type from an either of pairs. + /// + /// Here, the homogeneous type is the second element of the pairs. + /// + /// ``` + /// use either::*; + /// let left: Either<_, (String, u32)> = Left((vec![0], 123)); + /// assert_eq!(left.factor_second().1, 123); + /// + /// let right: Either<(Vec, u32), _> = Right((String::new(), 123)); + /// assert_eq!(right.factor_second().1, 123); + /// ``` + pub fn factor_second(self) -> (Either, T) { + match self { + Left((l, t)) => (Left(l), t), + Right((r, t)) => (Right(r), t), + } + } +} + +impl Either { + /// Extract the value of an either over two equivalent types. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.into_inner(), 123); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.into_inner(), 123); + /// ``` + pub fn into_inner(self) -> T { + either!(self, inner => inner) + } + + /// Map `f` over the contained value and return the result in the + /// corresponding variant. + /// + /// ``` + /// use either::*; + /// + /// let value: Either<_, i32> = Right(42); + /// + /// let other = value.map(|x| x * 2); + /// assert_eq!(other, Right(84)); + /// ``` + pub fn map(self, f: F) -> Either + where F: FnOnce(T) -> M + { + match self { + Left(l) => Left(f(l)), + Right(r) => Right(f(r)), + } + } +} + +/// Convert from `Result` to `Either` with `Ok => Right` and `Err => Left`. +impl From> for Either { + fn from(r: Result) -> Self { + match r { + Err(e) => Left(e), + Ok(o) => Right(o), + } + } +} + +/// Convert from `Either` to `Result` with `Right => Ok` and `Left => Err`. +impl Into> for Either { + fn into(self) -> Result { + match self { + Left(l) => Err(l), + Right(r) => Ok(r), + } + } +} + +impl Extend for Either + where L: Extend, R: Extend +{ + fn extend(&mut self, iter: T) + where T: IntoIterator + { + either!(*self, ref mut inner => inner.extend(iter)) + } +} + +/// `Either` is an iterator if both `L` and `R` are iterators. +impl Iterator for Either + where L: Iterator, R: Iterator +{ + type Item = L::Item; + + fn next(&mut self) -> Option { + either!(*self, ref mut inner => inner.next()) + } + + fn size_hint(&self) -> (usize, Option) { + either!(*self, ref inner => inner.size_hint()) + } + + fn fold(self, init: Acc, f: G) -> Acc + where G: FnMut(Acc, Self::Item) -> Acc, + { + either!(self, inner => inner.fold(init, f)) + } + + fn count(self) -> usize { + either!(self, inner => inner.count()) + } + + fn last(self) -> Option { + either!(self, inner => inner.last()) + } + + fn nth(&mut self, n: usize) -> Option { + either!(*self, ref mut inner => inner.nth(n)) + } + + fn collect(self) -> B + where B: iter::FromIterator + { + either!(self, inner => inner.collect()) + } + + fn all(&mut self, f: F) -> bool + where F: FnMut(Self::Item) -> bool + { + either!(*self, ref mut inner => inner.all(f)) + } +} + +impl DoubleEndedIterator for Either + where L: DoubleEndedIterator, R: DoubleEndedIterator +{ + fn next_back(&mut self) -> Option { + either!(*self, ref mut inner => inner.next_back()) + } +} + +impl ExactSizeIterator for Either + where L: ExactSizeIterator, R: ExactSizeIterator +{ +} + +#[cfg(any(test, feature = "use_std"))] +/// `Either` implements `Read` if both `L` and `R` do. +/// +/// Requires crate feature `"use_std"` +impl Read for Either + where L: Read, R: Read +{ + fn read(&mut self, buf: &mut [u8]) -> io::Result { + either!(*self, ref mut inner => inner.read(buf)) + } + + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + either!(*self, ref mut inner => inner.read_to_end(buf)) + } +} + +#[cfg(any(test, feature = "use_std"))] +/// Requires crate feature `"use_std"` +impl BufRead for Either + where L: BufRead, R: BufRead +{ + fn fill_buf(&mut self) -> io::Result<&[u8]> { + either!(*self, ref mut inner => inner.fill_buf()) + } + + fn consume(&mut self, amt: usize) { + either!(*self, ref mut inner => inner.consume(amt)) + } +} + +#[cfg(any(test, feature = "use_std"))] +/// `Either` implements `Write` if both `L` and `R` do. +/// +/// Requires crate feature `"use_std"` +impl Write for Either + where L: Write, R: Write +{ + fn write(&mut self, buf: &[u8]) -> io::Result { + either!(*self, ref mut inner => inner.write(buf)) + } + + fn flush(&mut self) -> io::Result<()> { + either!(*self, ref mut inner => inner.flush()) + } +} + +impl AsRef for Either + where L: AsRef, R: AsRef +{ + fn as_ref(&self) -> &Target { + either!(*self, ref inner => inner.as_ref()) + } +} + +macro_rules! impl_specific_ref_and_mut { + ($t:ty, $($attr:meta),* ) => { + $(#[$attr])* + impl AsRef<$t> for Either + where L: AsRef<$t>, R: AsRef<$t> + { + fn as_ref(&self) -> &$t { + either!(*self, ref inner => inner.as_ref()) + } + } + + $(#[$attr])* + impl AsMut<$t> for Either + where L: AsMut<$t>, R: AsMut<$t> + { + fn as_mut(&mut self) -> &mut $t { + either!(*self, ref mut inner => inner.as_mut()) + } + } + }; +} + +impl_specific_ref_and_mut!(str,); +impl_specific_ref_and_mut!( + ::std::path::Path, + cfg(feature = "use_std"), + doc = "Requires crate feature `use_std`." +); +impl_specific_ref_and_mut!( + ::std::ffi::OsStr, + cfg(feature = "use_std"), + doc = "Requires crate feature `use_std`." +); +impl_specific_ref_and_mut!( + ::std::ffi::CStr, + cfg(feature = "use_std"), + doc = "Requires crate feature `use_std`." +); + +impl AsRef<[Target]> for Either + where L: AsRef<[Target]>, R: AsRef<[Target]> +{ + fn as_ref(&self) -> &[Target] { + either!(*self, ref inner => inner.as_ref()) + } +} + +impl AsMut for Either + where L: AsMut, R: AsMut +{ + fn as_mut(&mut self) -> &mut Target { + either!(*self, ref mut inner => inner.as_mut()) + } +} + +impl AsMut<[Target]> for Either + where L: AsMut<[Target]>, R: AsMut<[Target]> +{ + fn as_mut(&mut self) -> &mut [Target] { + either!(*self, ref mut inner => inner.as_mut()) + } +} + +impl Deref for Either + where L: Deref, R: Deref +{ + type Target = L::Target; + + fn deref(&self) -> &Self::Target { + either!(*self, ref inner => &*inner) + } +} + +impl DerefMut for Either + where L: DerefMut, R: DerefMut +{ + fn deref_mut(&mut self) -> &mut Self::Target { + either!(*self, ref mut inner => &mut *inner) + } +} + +#[cfg(any(test, feature = "use_std"))] +/// `Either` implements `Error` if *both* `L` and `R` implement it. +impl Error for Either + where L: Error, R: Error +{ + fn description(&self) -> &str { + either!(*self, ref inner => inner.description()) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&Error> { + either!(*self, ref inner => inner.cause()) + } +} + +impl fmt::Display for Either + where L: fmt::Display, R: fmt::Display +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + either!(*self, ref inner => inner.fmt(f)) + } +} + +#[test] +fn basic() { + let mut e = Left(2); + let r = Right(2); + assert_eq!(e, Left(2)); + e = r; + assert_eq!(e, Right(2)); + assert_eq!(e.left(), None); + assert_eq!(e.right(), Some(2)); + assert_eq!(e.as_ref().right(), Some(&2)); + assert_eq!(e.as_mut().right(), Some(&mut 2)); +} + +#[test] +fn macros() { + fn a() -> Either { + let x: u32 = try_left!(Right(1337u32)); + Left(x * 2) + } + assert_eq!(a(), Right(1337)); + + fn b() -> Either { + Right(try_right!(Left("foo bar"))) + } + assert_eq!(b(), Left(String::from("foo bar"))); +} + +#[test] +fn deref() { + fn is_str(_: &str) {} + let value: Either = Left(String::from("test")); + is_str(&*value); +} + +#[test] +fn iter() { + let x = 3; + let mut iter = match x { + 3 => Left(0..10), + _ => Right(17..), + }; + + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.count(), 9); +} + +#[test] +fn read_write() { + use std::io; + + let use_stdio = false; + let mockdata = [0xff; 256]; + + let mut reader = if use_stdio { + Left(io::stdin()) + } else { + Right(&mockdata[..]) + }; + + let mut buf = [0u8; 16]; + assert_eq!(reader.read(&mut buf).unwrap(), buf.len()); + assert_eq!(&buf, &mockdata[..buf.len()]); + + let mut mockbuf = [0u8; 256]; + let mut writer = if use_stdio { + Left(io::stdout()) + } else { + Right(&mut mockbuf[..]) + }; + + let buf = [1u8; 16]; + assert_eq!(writer.write(&buf).unwrap(), buf.len()); +} + +#[test] +fn error() { + let invalid_utf8 = b"\xff"; + let res = || -> Result<_, Either<_, _>> { + try!(::std::str::from_utf8(invalid_utf8).map_err(Left)); + try!("x".parse::().map_err(Right)); + Ok(()) + }(); + assert!(res.is_err()); + res.unwrap_err().description(); // make sure this can be called +} + +/// A helper macro to check if AsRef and AsMut are implemented for a given type. +macro_rules! check_t { + ($t:ty) => {{ + fn check_ref>() {} + fn propagate_ref, T2: AsRef<$t>>() { + check_ref::>() + } + fn check_mut>() {} + fn propagate_mut, T2: AsMut<$t>>() { + check_mut::>() + } + }}; +} + +// This "unused" method is here to ensure that compilation doesn't fail on given types. +fn _unsized_ref_propagation() { + check_t!(str); + + fn check_array_ref, Item>() {} + fn check_array_mut, Item>() {} + + fn propagate_array_ref, T2: AsRef<[Item]>, Item>() { + check_array_ref::, _>() + } + + fn propagate_array_mut, T2: AsMut<[Item]>, Item>() { + check_array_mut::, _>() + } +} + +// This "unused" method is here to ensure that compilation doesn't fail on given types. +#[cfg(feature = "use_std")] +fn _unsized_std_propagation() { + check_t!(::std::path::Path); + check_t!(::std::ffi::OsStr); + check_t!(::std::ffi::CStr); +} diff --git a/src/rust/vendor/itertools/.cargo-checksum.json b/src/rust/vendor/itertools/.cargo-checksum.json new file mode 100644 index 000000000..1c535f987 --- /dev/null +++ b/src/rust/vendor/itertools/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"31d5b840f465cdc6697fddf4b2227969f68d6948c374c4ceadc8eff2b8857f0c","Cargo.lock":"eebdb4d7cd2d0744fb7c469cd43d80f39ea90c5319f6aa23cab94fd2e6c7271b","Cargo.toml":"48b6a4509d3716af7f114d30abe6a29d8430c23d00d51a0cd526db2c7046c1ca","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.rst":"e6bb15fcba6c23020d1a0a13c84d290188a897cf4a9ae5ab37176032371ba08f","benches/bench1.rs":"bb06f39db0544b1380cd4929139ccf521a9eecab7ca3f910b9499f965ec0a047","benches/combinations_with_replacement.rs":"11f29160652a2d90ce7ca4b1c339c4457888ab6867e2456ce1c62e3adf9be737","benches/extra/mod.rs":"6ca290d72302a1945078621610b5788060b0de29639decebbdc557a80044aa97","benches/extra/zipslices.rs":"3db9764c21536c541cdf3f93ba2e34f6ab63dd12a9149aa5bd8a4524778176f1","benches/fold_specialization.rs":"9f5b137afc033e1e00609bb353ab79764a3515c0d129a3ba251368e00db61cd5","benches/tree_fold1.rs":"539232e74f9aaea295a42069ac5af707811e90dc1c71c6e0a9064ffc731999de","benches/tuple_combinations.rs":"20317c18e9ae42d50b341880c71081ab1aaa5b281aa74ce14707b291ba87d7b0","benches/tuples.rs":"5a620783ae203e9ff9623d10d2c7fe9911d8b6c811cbad7613afa30e390c759d","examples/iris.data":"596ffd580471ca4d4880f8e439c7281f3b50d8249a5960353cb200b1490f63a0","examples/iris.rs":"15483be8a439e1c6c32d96b84dd30b6b2fadb584cae09a057a0cacda8180416a","src/adaptors/mod.rs":"fdbd9452de37639e1b48f4dfad84f35a3f162a05b0570f3e7dc7774d05716761","src/adaptors/multi_product.rs":"0acbb29eba50a057fb83408ae83eb275b1c4f4ad41fa82be815ca37274ef7c2a","src/combinations.rs":"f40f6d332ada63b001bf17cded0ee99d2e29eef6a3211586409720e95c58e468","src/combinations_with_replacement.rs":"3fe1d2f40d4d047f3f05def2b9eb3acf46f5fe1cf66349551969b4963df56696","src/concat_impl.rs":"450d5640ba7e968ff8f2855b9cf60fca82f06f62590dc2348b9ef8bfa4224231","src/cons_tuples_impl.rs":"4c2167fd1f840c50b08a8e8fbcc9d4c318469c4065eaa92835fdf1c7c60b416c","src/diff.rs":"bb90542a685a76b58ee367e88c66c436fa3306c69a25ce9217f7886919c37868","src/either_or_both.rs":"a3fe2e651660e7d8f05367f5c07e91ce60bf42ea32a89c7b3e1b8f0ee01651bf","src/exactly_one_err.rs":"423c089bd1954c0ab721195df633e04d25e39c612fbbcec6bca5df5c3a0c9411","src/format.rs":"8f74682be045c48d59671af2077687b8ada63b05230b0d0c48a08266b4ab75c1","src/free.rs":"5e7a8b363aaa639fe2895668a45d577a06072ce4785c6639385152bf4c423db2","src/group_map.rs":"872d6e243e649ad30c94973c034596cc3377b10018e361bca07e11c612006de6","src/groupbylazy.rs":"404f44d3920e36f92274fd53229cecdb95da94ed3886d329f085b9a9828f0ae5","src/impl_macros.rs":"18d55fe8cf59e0088cc09115601688aa54ade3148069bb6ebf88305eafbaeac7","src/intersperse.rs":"78000b821190b6d5e6f0fac75cf13f20ea35d9261952562f1a27c6b50a390d5f","src/kmerge_impl.rs":"fa5c5ddc916273cb30f88cc8deb17c9ed44346eb658029cecc39fc779caa630d","src/lazy_buffer.rs":"7e479db2b2df8e64a63108ade2d7861116afc13e26a504660b54bd5ead97895b","src/lib.rs":"100fb67af1fb70a168bb37186c550cb10afa810582ffb6a1b1bca10139141d2b","src/merge_join.rs":"928c4ade1adf921b41f8eea50e113e113ed9036d336a97957b4cbb3787748a39","src/minmax.rs":"4668a7f824fbc133599f43ffb6f7283e5bd603e07df2d8176abc6f25d6af9db0","src/multipeek_impl.rs":"fc8a177fd96e1f0dd6a1a13f3c0625cbe0e6ca914af25e46cec86ea5434ef7f3","src/pad_tail.rs":"8de020e05dd959ae19cc33f8c57e8d50378964c61136dd0ab95182f9a979a21d","src/peeking_take_while.rs":"a15ed841d217145e5ab2d13612bff7b7de5fb1274528af891574b84177133188","src/permutations.rs":"7322443db3ca5c52edcfd9564ba45c544ba3ae6dcbabd44f0c5d2f91c1745c77","src/process_results_impl.rs":"cd85c14725cd82f6b6b0b9fa97c25d383295094ac4154b929706f97af495fa51","src/put_back_n_impl.rs":"fa21109d180973821f41d3f7e4d29b377b3d4910d4d5ca1cab3d7a0085c33fd7","src/rciter_impl.rs":"fb0a13ea76531f9e549d758a78b4a7a19a1d9a9ceeb73946f5f3832895e545bd","src/repeatn.rs":"7fc91a65cd05bb2e8776edcacbe6407eb8a329a59918e72f0c83592db429a881","src/size_hint.rs":"c1d35b422a696cf3d63e7c90d8f9fdf01a304cf8156e914287c4ef48fea62dd3","src/sources.rs":"7667bf1d40f0fe47400d01438dc55b6e33bb339e93c2adade82900eea061cd26","src/tee.rs":"c50561be52f24ef1b76c23032acbe476823a83c47be4084498cee72cdd9cc690","src/tuple_impl.rs":"00b8f2d765a82b5427041831576259b7a8d7d67b653cf33bb64b871e29fa96e1","src/unique_impl.rs":"58f61e031f7f7aadb2fd7ea7e660f43ca2f5ec00dec79c3231a6206d35ce7815","src/with_position.rs":"dc3e619f637e533d15919d26b641f49f3e62e7b8eed0a8a4aa8f058f9c4581be","src/zip_eq_impl.rs":"f857c69120255db16ad6ddec628c79cb573b1d5179fcebab1906bf5b762c02e3","src/zip_longest.rs":"c785582f5b56df4c8503cbe9e527d0bef264f97df75c013964fa634b5ada8103","src/ziptuple.rs":"d7ae7d3c33185ad74ab2bba750ac337b5c236750cc8341dd9883faf6465712a1","tests/adaptors_no_collect.rs":"dc69691bed895e6fd3922942ccc7d424a5247b0f79dea74cf8e2f8a8af0bd491","tests/fold_specialization.rs":"fc86706ccbbc5c1dd43e0eaff046352e7f3cbcc2ee569ab1fc910db643cba37b","tests/merge_join.rs":"b08c4ee6529d234c68d411a413b8781455d18a1eab17872d1828bb75a4fcf79b","tests/peeking_take_while.rs":"4b1c394e44a9ef9bc0de707ae080b45803db722f79834c20f15b826d7c3f1f2e","tests/quick.rs":"ed0dbcd28692d4672f88d5d3517e7fdf257a8accae350d859f594529b837ece3","tests/specializations.rs":"e073e3617419b6518783b5ccd4e3fc0a9a471156dcc5fa77da481b4d3bb9a3e5","tests/test_core.rs":"c5c6546539649e319ca8a44e033f2c762468628d5ce4170790d0ba01c2e0e2e6","tests/test_std.rs":"944901d44b0e1ac02bfd9a84d6b11657abf3aa3423a5317512c6b28b22c3b262","tests/tuples.rs":"014e4da776174bfe923270e2a359cd9c95b372fce4b952b8138909d6e2c52762","tests/zip.rs":"09149f5d9bd2f586c346ef442d07f9240c7efe0b8437fb5c1fc1014be516c275"},"package":"284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"} \ No newline at end of file diff --git a/src/rust/vendor/itertools/CHANGELOG.md b/src/rust/vendor/itertools/CHANGELOG.md new file mode 100644 index 000000000..67633ab75 --- /dev/null +++ b/src/rust/vendor/itertools/CHANGELOG.md @@ -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>` 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`, 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::()` that iterates by two, three or four elements at a time (where `T` is a tuple type). + - Add `.tuple_windows::()` that iterates using a window of the two, three or four most recent elements. + - Add `.next_tuple::()` 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` 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* diff --git a/src/rust/vendor/itertools/Cargo.lock b/src/rust/vendor/itertools/Cargo.lock new file mode 100644 index 000000000..917f2124a --- /dev/null +++ b/src/rust/vendor/itertools/Cargo.lock @@ -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" diff --git a/src/rust/vendor/itertools/Cargo.toml b/src/rust/vendor/itertools/Cargo.toml new file mode 100644 index 000000000..d8a9b8cd3 --- /dev/null +++ b/src/rust/vendor/itertools/Cargo.toml @@ -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 = [] diff --git a/src/rust/vendor/itertools/LICENSE-APACHE b/src/rust/vendor/itertools/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/src/rust/vendor/itertools/LICENSE-APACHE @@ -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. diff --git a/src/rust/vendor/itertools/LICENSE-MIT b/src/rust/vendor/itertools/LICENSE-MIT new file mode 100644 index 000000000..9203baa05 --- /dev/null +++ b/src/rust/vendor/itertools/LICENSE-MIT @@ -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. diff --git a/src/rust/vendor/itertools/README.rst b/src/rust/vendor/itertools/README.rst new file mode 100644 index 000000000..24c99d3e7 --- /dev/null +++ b/src/rust/vendor/itertools/README.rst @@ -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 `_, +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``, +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. diff --git a/src/rust/vendor/itertools/benches/bench1.rs b/src/rust/vendor/itertools/benches/bench1.rs new file mode 100644 index 000000000..71278d17b --- /dev/null +++ b/src/rust/vendor/itertools/benches/bench1.rs @@ -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(iter: I) -> I::Item + where I: IntoIterator, + I::Item: Default + Add +{ + 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); + + impl Iterator for NewIterator { + type Item = usize; + + fn next(&mut self) -> Option { + 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); diff --git a/src/rust/vendor/itertools/benches/combinations_with_replacement.rs b/src/rust/vendor/itertools/benches/combinations_with_replacement.rs new file mode 100644 index 000000000..8e4fa3dc3 --- /dev/null +++ b/src/rust/vendor/itertools/benches/combinations_with_replacement.rs @@ -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); diff --git a/src/rust/vendor/itertools/benches/extra/mod.rs b/src/rust/vendor/itertools/benches/extra/mod.rs new file mode 100644 index 000000000..52fe5cc3f --- /dev/null +++ b/src/rust/vendor/itertools/benches/extra/mod.rs @@ -0,0 +1,2 @@ +pub use self::zipslices::ZipSlices; +mod zipslices; diff --git a/src/rust/vendor/itertools/benches/extra/zipslices.rs b/src/rust/vendor/itertools/benches/extra/zipslices.rs new file mode 100644 index 000000000..8bf3967f5 --- /dev/null +++ b/src/rust/vendor/itertools/benches/extra/zipslices.rs @@ -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` 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: 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 ZipSlices + 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 Iterator for ZipSlices + where T: Slice, + U: Slice +{ + type Item = (T::Item, U::Item); + + #[inline(always)] + fn next(&mut self) -> Option { + 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) { + let len = self.len - self.index; + (len, Some(len)) + } +} + +impl DoubleEndedIterator for ZipSlices + where T: Slice, + U: Slice +{ + #[inline(always)] + fn next_back(&mut self) -> Option { + 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 ExactSizeIterator for ZipSlices + where T: Slice, + U: Slice +{} + +unsafe impl Slice for ZipSlices + 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); +} diff --git a/src/rust/vendor/itertools/benches/fold_specialization.rs b/src/rust/vendor/itertools/benches/fold_specialization.rs new file mode 100644 index 000000000..53319a55c --- /dev/null +++ b/src/rust/vendor/itertools/benches/fold_specialization.rs @@ -0,0 +1,73 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use itertools::Itertools; + +struct Unspecialized(I); + +impl Iterator for Unspecialized +where I: Iterator +{ + type Item = I::Item; + + #[inline(always)] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + 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); diff --git a/src/rust/vendor/itertools/benches/tree_fold1.rs b/src/rust/vendor/itertools/benches/tree_fold1.rs new file mode 100644 index 000000000..f12995db8 --- /dev/null +++ b/src/rust/vendor/itertools/benches/tree_fold1.rs @@ -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(self, mut f: F) -> Option + where F: FnMut(Self::Item, Self::Item) -> Self::Item, + Self: Sized, + { + let hint = self.size_hint().0; + let cap = std::mem::size_of::() * 8 - hint.leading_zeros() as usize; + let mut stack = Vec::with_capacity(cap); + 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 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 = (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 = (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, +); diff --git a/src/rust/vendor/itertools/benches/tuple_combinations.rs b/src/rust/vendor/itertools/benches/tuple_combinations.rs new file mode 100644 index 000000000..84411efd8 --- /dev/null +++ b/src/rust/vendor/itertools/benches/tuple_combinations.rs @@ -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); diff --git a/src/rust/vendor/itertools/benches/tuples.rs b/src/rust/vendor/itertools/benches/tuples.rs new file mode 100644 index 000000000..ea50aaaee --- /dev/null +++ b/src/rust/vendor/itertools/benches/tuples.rs @@ -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 = (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 = (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 = (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 = (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 = (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 = (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, +); diff --git a/src/rust/vendor/itertools/examples/iris.data b/src/rust/vendor/itertools/examples/iris.data new file mode 100644 index 000000000..a3490e0e0 --- /dev/null +++ b/src/rust/vendor/itertools/examples/iris.data @@ -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 diff --git a/src/rust/vendor/itertools/examples/iris.rs b/src/rust/vendor/itertools/examples/iris.rs new file mode 100644 index 000000000..25ab373f7 --- /dev/null +++ b/src/rust/vendor/itertools/examples/iris.rs @@ -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 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 { + 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::()?; + } + 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(" ")) + } + } +} diff --git a/src/rust/vendor/itertools/src/adaptors/mod.rs b/src/rust/vendor/itertools/src/adaptors/mod.rs new file mode 100644 index 000000000..7d61f117c --- /dev/null +++ b/src/rust/vendor/itertools/src/adaptors/mod.rs @@ -0,0 +1,1260 @@ +//! 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. + +mod multi_product; +#[cfg(feature = "use_std")] +pub use self::multi_product::*; + +use std::fmt; +use std::mem::replace; +use std::iter::{Fuse, Peekable, FromIterator}; +use std::marker::PhantomData; +use crate::size_hint; + +/// An iterator adaptor that alternates elements from two iterators until both +/// run out. +/// +/// This iterator is *fused*. +/// +/// See [`.interleave()`](../trait.Itertools.html#method.interleave) for more information. +#[derive(Clone, Debug)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct Interleave { + a: Fuse, + b: Fuse, + flag: bool, +} + +/// Create an iterator that interleaves elements in `i` and `j`. +/// +/// `IntoIterator` enabled version of `i.interleave(j)`. +/// +/// ``` +/// use itertools::interleave; +/// +/// for elt in interleave(&[1, 2, 3], &[2, 3, 4]) { +/// /* loop body */ +/// } +/// ``` +pub fn interleave(i: I, j: J) -> Interleave<::IntoIter, ::IntoIter> + where I: IntoIterator, + J: IntoIterator +{ + Interleave { + a: i.into_iter().fuse(), + b: j.into_iter().fuse(), + flag: false, + } +} + +impl Iterator for Interleave + where I: Iterator, + J: Iterator +{ + type Item = I::Item; + #[inline] + fn next(&mut self) -> Option { + self.flag = !self.flag; + if self.flag { + match self.a.next() { + None => self.b.next(), + r => r, + } + } else { + match self.b.next() { + None => self.a.next(), + r => r, + } + } + } + + fn size_hint(&self) -> (usize, Option) { + size_hint::add(self.a.size_hint(), self.b.size_hint()) + } +} + +/// An iterator adaptor that alternates elements from the two iterators until +/// one of them runs out. +/// +/// This iterator is *fused*. +/// +/// See [`.interleave_shortest()`](../trait.Itertools.html#method.interleave_shortest) +/// for more information. +#[derive(Clone, Debug)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct InterleaveShortest + where I: Iterator, + J: Iterator +{ + it0: I, + it1: J, + phase: bool, // false ==> it0, true ==> it1 +} + +/// Create a new `InterleaveShortest` iterator. +pub fn interleave_shortest(a: I, b: J) -> InterleaveShortest + where I: Iterator, + J: Iterator +{ + InterleaveShortest { + it0: a, + it1: b, + phase: false, + } +} + +impl Iterator for InterleaveShortest + where I: Iterator, + J: Iterator +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.phase { + false => match self.it0.next() { + None => None, + e => { + self.phase = true; + e + } + }, + true => match self.it1.next() { + None => None, + e => { + self.phase = false; + e + } + }, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (curr_hint, next_hint) = { + let it0_hint = self.it0.size_hint(); + let it1_hint = self.it1.size_hint(); + if self.phase { + (it1_hint, it0_hint) + } else { + (it0_hint, it1_hint) + } + }; + let (curr_lower, curr_upper) = curr_hint; + let (next_lower, next_upper) = next_hint; + let (combined_lower, combined_upper) = + size_hint::mul_scalar(size_hint::min(curr_hint, next_hint), 2); + let lower = + if curr_lower > next_lower { + combined_lower + 1 + } else { + combined_lower + }; + let upper = { + let extra_elem = match (curr_upper, next_upper) { + (_, None) => false, + (None, Some(_)) => true, + (Some(curr_max), Some(next_max)) => curr_max > next_max, + }; + if extra_elem { + combined_upper.and_then(|x| x.checked_add(1)) + } else { + combined_upper + } + }; + (lower, upper) + } +} + +#[derive(Clone, Debug)] +/// An iterator adaptor that allows putting back a single +/// item to the front of the iterator. +/// +/// Iterator element type is `I::Item`. +pub struct PutBack + where I: Iterator +{ + top: Option, + iter: I, +} + +/// Create an iterator where you can put back a single item +pub fn put_back(iterable: I) -> PutBack + where I: IntoIterator +{ + PutBack { + top: None, + iter: iterable.into_iter(), + } +} + +impl PutBack + where I: Iterator +{ + /// put back value `value` (builder method) + pub fn with_value(mut self, value: I::Item) -> Self { + self.put_back(value); + self + } + + /// Split the `PutBack` into its parts. + #[inline] + pub fn into_parts(self) -> (Option, I) { + let PutBack{top, iter} = self; + (top, iter) + } + + /// Put back a single value to the front of the iterator. + /// + /// If a value is already in the put back slot, it is overwritten. + #[inline] + pub fn put_back(&mut self, x: I::Item) { + self.top = Some(x) + } +} + +impl Iterator for PutBack + where I: Iterator +{ + type Item = I::Item; + #[inline] + fn next(&mut self) -> Option { + match self.top { + None => self.iter.next(), + ref mut some => some.take(), + } + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + // Not ExactSizeIterator because size may be larger than usize + size_hint::add_scalar(self.iter.size_hint(), self.top.is_some() as usize) + } + + fn count(self) -> usize { + self.iter.count() + (self.top.is_some() as usize) + } + + fn last(self) -> Option { + self.iter.last().or(self.top) + } + + fn nth(&mut self, n: usize) -> Option { + match self.top { + None => self.iter.nth(n), + ref mut some => { + if n == 0 { + some.take() + } else { + *some = None; + self.iter.nth(n - 1) + } + } + } + } + + fn all(&mut self, mut f: G) -> bool + where G: FnMut(Self::Item) -> bool + { + if let Some(elt) = self.top.take() { + if !f(elt) { + return false; + } + } + self.iter.all(f) + } + + fn fold(mut self, init: Acc, mut f: G) -> Acc + where G: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + if let Some(elt) = self.top.take() { + accum = f(accum, elt); + } + self.iter.fold(accum, f) + } +} + +#[derive(Debug, Clone)] +/// An iterator adaptor that iterates over the cartesian product of +/// the element sets of two iterators `I` and `J`. +/// +/// Iterator element type is `(I::Item, J::Item)`. +/// +/// See [`.cartesian_product()`](../trait.Itertools.html#method.cartesian_product) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct Product + where I: Iterator +{ + a: I, + a_cur: Option, + b: J, + b_orig: J, +} + +/// Create a new cartesian product iterator +/// +/// Iterator element type is `(I::Item, J::Item)`. +pub fn cartesian_product(mut i: I, j: J) -> Product + where I: Iterator, + J: Clone + Iterator, + I::Item: Clone +{ + Product { + a_cur: i.next(), + a: i, + b: j.clone(), + b_orig: j, + } +} + + +impl Iterator for Product + where I: Iterator, + J: Clone + Iterator, + I::Item: Clone +{ + type Item = (I::Item, J::Item); + fn next(&mut self) -> Option<(I::Item, J::Item)> { + let elt_b = match self.b.next() { + None => { + self.b = self.b_orig.clone(); + match self.b.next() { + None => return None, + Some(x) => { + self.a_cur = self.a.next(); + x + } + } + } + Some(x) => x + }; + match self.a_cur { + None => None, + Some(ref a) => { + Some((a.clone(), elt_b)) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let has_cur = self.a_cur.is_some() as usize; + // Not ExactSizeIterator because size may be larger than usize + let (b_min, b_max) = self.b.size_hint(); + + // Compute a * b_orig + b for both lower and upper bound + size_hint::add( + size_hint::mul(self.a.size_hint(), self.b_orig.size_hint()), + (b_min * has_cur, b_max.map(move |x| x * has_cur))) + } + + fn fold(mut self, mut accum: Acc, mut f: G) -> Acc + where G: FnMut(Acc, Self::Item) -> Acc, + { + // use a split loop to handle the loose a_cur as well as avoiding to + // clone b_orig at the end. + if let Some(mut a) = self.a_cur.take() { + let mut b = self.b; + loop { + accum = b.fold(accum, |acc, elt| f(acc, (a.clone(), elt))); + + // we can only continue iterating a if we had a first element; + if let Some(next_a) = self.a.next() { + b = self.b_orig.clone(); + a = next_a; + } else { + break; + } + } + } + accum + } +} + +/// A “meta iterator adaptor”. Its closure receives a reference to the iterator +/// and may pick off as many elements as it likes, to produce the next iterator element. +/// +/// Iterator element type is *X*, if the return type of `F` is *Option\*. +/// +/// See [`.batching()`](../trait.Itertools.html#method.batching) for more information. +#[derive(Clone)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct Batching { + f: F, + iter: I, +} + +impl fmt::Debug for Batching where I: fmt::Debug { + debug_fmt_fields!(Batching, iter); +} + +/// Create a new Batching iterator. +pub fn batching(iter: I, f: F) -> Batching { + Batching { f, iter } +} + +impl Iterator for Batching + where I: Iterator, + F: FnMut(&mut I) -> Option +{ + type Item = B; + #[inline] + fn next(&mut self) -> Option { + (self.f)(&mut self.iter) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // No information about closue behavior + (0, None) + } +} + +/// An iterator adaptor that steps a number elements in the base iterator +/// for each iteration. +/// +/// The iterator steps by yielding the next element from the base iterator, +/// then skipping forward *n-1* elements. +/// +/// See [`.step()`](../trait.Itertools.html#method.step) for more information. +#[deprecated(note="Use std .step_by() instead", since="0.8")] +#[allow(deprecated)] +#[derive(Clone, Debug)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct Step { + iter: Fuse, + skip: usize, +} + +/// Create a `Step` iterator. +/// +/// **Panics** if the step is 0. +#[allow(deprecated)] +pub fn step(iter: I, step: usize) -> Step + where I: Iterator +{ + assert!(step != 0); + Step { + iter: iter.fuse(), + skip: step - 1, + } +} + +#[allow(deprecated)] +impl Iterator for Step + where I: Iterator +{ + type Item = I::Item; + #[inline] + fn next(&mut self) -> Option { + let elt = self.iter.next(); + if self.skip > 0 { + self.iter.nth(self.skip - 1); + } + elt + } + + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.iter.size_hint(); + let div = |x: usize| { + if x == 0 { + 0 + } else { + 1 + (x - 1) / (self.skip + 1) + } + }; + (div(low), high.map(div)) + } +} + +// known size +#[allow(deprecated)] +impl ExactSizeIterator for Step + where I: ExactSizeIterator +{} + +pub trait MergePredicate { + fn merge_pred(&mut self, a: &T, b: &T) -> bool; +} + +#[derive(Clone)] +pub struct MergeLte; + +impl MergePredicate for MergeLte { + fn merge_pred(&mut self, a: &T, b: &T) -> bool { + a <= b + } +} + +/// An iterator adaptor that merges the two base iterators in ascending order. +/// If both base iterators are sorted (ascending), the result is sorted. +/// +/// Iterator element type is `I::Item`. +/// +/// See [`.merge()`](../trait.Itertools.html#method.merge_by) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub type Merge = MergeBy; + +/// Create an iterator that merges elements in `i` and `j`. +/// +/// `IntoIterator` enabled version of `i.merge(j)`. +/// +/// ``` +/// use itertools::merge; +/// +/// for elt in merge(&[1, 2, 3], &[2, 3, 4]) { +/// /* loop body */ +/// } +/// ``` +pub fn merge(i: I, j: J) -> Merge<::IntoIter, ::IntoIter> + where I: IntoIterator, + J: IntoIterator, + I::Item: PartialOrd +{ + merge_by_new(i, j, MergeLte) +} + +/// An iterator adaptor that merges the two base iterators in ascending order. +/// If both base iterators are sorted (ascending), the result is sorted. +/// +/// Iterator element type is `I::Item`. +/// +/// See [`.merge_by()`](../trait.Itertools.html#method.merge_by) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct MergeBy + where I: Iterator, + J: Iterator +{ + a: Peekable, + b: Peekable, + fused: Option, + cmp: F, +} + +impl fmt::Debug for MergeBy + where I: Iterator + fmt::Debug, J: Iterator + fmt::Debug, + I::Item: fmt::Debug, +{ + debug_fmt_fields!(MergeBy, a, b); +} + +implbool> MergePredicate for F { + fn merge_pred(&mut self, a: &T, b: &T) -> bool { + self(a, b) + } +} + +/// Create a `MergeBy` iterator. +pub fn merge_by_new(a: I, b: J, cmp: F) -> MergeBy + where I: IntoIterator, + J: IntoIterator, + F: MergePredicate, +{ + MergeBy { + a: a.into_iter().peekable(), + b: b.into_iter().peekable(), + fused: None, + cmp, + } +} + +impl Clone for MergeBy + where I: Iterator, + J: Iterator, + Peekable: Clone, + Peekable: Clone, + F: Clone +{ + clone_fields!(a, b, fused, cmp); +} + +impl Iterator for MergeBy + where I: Iterator, + J: Iterator, + F: MergePredicate +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + let less_than = match self.fused { + Some(lt) => lt, + None => match (self.a.peek(), self.b.peek()) { + (Some(a), Some(b)) => self.cmp.merge_pred(a, b), + (Some(_), None) => { + self.fused = Some(true); + true + } + (None, Some(_)) => { + self.fused = Some(false); + false + } + (None, None) => return None, + } + }; + if less_than { + self.a.next() + } else { + self.b.next() + } + } + + fn size_hint(&self) -> (usize, Option) { + // Not ExactSizeIterator because size may be larger than usize + size_hint::add(self.a.size_hint(), self.b.size_hint()) + } +} + +#[derive(Clone, Debug)] +pub struct CoalesceCore + where I: Iterator +{ + iter: I, + last: Option, +} + +impl CoalesceCore + where I: Iterator +{ + fn next_with(&mut self, mut f: F) -> Option + where F: FnMut(I::Item, I::Item) -> Result + { + // this fuses the iterator + let mut last = match self.last.take() { + None => return None, + Some(x) => x, + }; + for next in &mut self.iter { + match f(last, next) { + Ok(joined) => last = joined, + Err((last_, next_)) => { + self.last = Some(next_); + return Some(last_); + } + } + } + + Some(last) + } + + fn size_hint(&self) -> (usize, Option) { + let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), + self.last.is_some() as usize); + ((low > 0) as usize, hi) + } +} + +/// An iterator adaptor that may join together adjacent elements. +/// +/// See [`.coalesce()`](../trait.Itertools.html#method.coalesce) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct Coalesce + where I: Iterator +{ + iter: CoalesceCore, + f: F, +} + +impl Clone for Coalesce + where I: Iterator, + I::Item: Clone +{ + clone_fields!(iter, f); +} + +impl fmt::Debug for Coalesce + where I: Iterator + fmt::Debug, + I::Item: fmt::Debug, +{ + debug_fmt_fields!(Coalesce, iter); +} + +/// Create a new `Coalesce`. +pub fn coalesce(mut iter: I, f: F) -> Coalesce + where I: Iterator +{ + Coalesce { + iter: CoalesceCore { + last: iter.next(), + iter, + }, + f, + } +} + +impl Iterator for Coalesce + where I: Iterator, + F: FnMut(I::Item, I::Item) -> Result +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + self.iter.next_with(&mut self.f) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function. +/// +/// See [`.dedup_by()`](../trait.Itertools.html#method.dedup_by) or [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct DedupBy + where I: Iterator +{ + iter: CoalesceCore, + dedup_pred: Pred, +} + +pub trait DedupPredicate { // TODO replace by Fn(&T, &T)->bool once Rust supports it + fn dedup_pair(&mut self, a: &T, b: &T) -> bool; +} + +#[derive(Clone)] +pub struct DedupEq; + +impl DedupPredicate for DedupEq { + fn dedup_pair(&mut self, a: &T, b: &T) -> bool { + a==b + } +} + +implbool> DedupPredicate for F { + fn dedup_pair(&mut self, a: &T, b: &T) -> bool { + self(a, b) + } +} + +/// An iterator adaptor that removes repeated duplicates. +/// +/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. +pub type Dedup=DedupBy; + +impl Clone for DedupBy + where I: Iterator, + I::Item: Clone, +{ + clone_fields!(iter, dedup_pred); +} + +/// Create a new `DedupBy`. +pub fn dedup_by(mut iter: I, dedup_pred: Pred) -> DedupBy + where I: Iterator, +{ + DedupBy { + iter: CoalesceCore { + last: iter.next(), + iter, + }, + dedup_pred, + } +} + +/// Create a new `Dedup`. +pub fn dedup(iter: I) -> Dedup + where I: Iterator +{ + dedup_by(iter, DedupEq) +} + +impl fmt::Debug for DedupBy + where I: Iterator + fmt::Debug, + I::Item: fmt::Debug, +{ + debug_fmt_fields!(Dedup, iter); +} + +impl Iterator for DedupBy + where I: Iterator, + Pred: DedupPredicate, +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + let ref mut dedup_pred = self.dedup_pred; + self.iter.next_with(|x, y| { + if dedup_pred.dedup_pair(&x, &y) { Ok(x) } else { Err((x, y)) } + }) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, mut accum: Acc, mut f: G) -> Acc + where G: FnMut(Acc, Self::Item) -> Acc, + { + if let Some(mut last) = self.iter.last { + let mut dedup_pred = self.dedup_pred; + accum = self.iter.iter.fold(accum, |acc, elt| { + if dedup_pred.dedup_pair(&elt, &last) { + acc + } else { + f(acc, replace(&mut last, elt)) + } + }); + f(accum, last) + } else { + accum + } + } +} + +/// An iterator adaptor that borrows from a `Clone`-able iterator +/// to only pick off elements while the predicate returns `true`. +/// +/// See [`.take_while_ref()`](../trait.Itertools.html#method.take_while_ref) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct TakeWhileRef<'a, I: 'a, F> { + iter: &'a mut I, + f: F, +} + +impl<'a, I, F> fmt::Debug for TakeWhileRef<'a, I, F> + where I: Iterator + fmt::Debug, +{ + debug_fmt_fields!(TakeWhileRef, iter); +} + +/// Create a new `TakeWhileRef` from a reference to clonable iterator. +pub fn take_while_ref(iter: &mut I, f: F) -> TakeWhileRef + where I: Iterator + Clone +{ + TakeWhileRef { iter, f } +} + +impl<'a, I, F> Iterator for TakeWhileRef<'a, I, F> + where I: Iterator + Clone, + F: FnMut(&I::Item) -> bool +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + let old = self.iter.clone(); + match self.iter.next() { + None => None, + Some(elt) => { + if (self.f)(&elt) { + Some(elt) + } else { + *self.iter = old; + None + } + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let (_, hi) = self.iter.size_hint(); + (0, hi) + } +} + +/// An iterator adaptor that filters `Option` iterator elements +/// and produces `A`. Stops on the first `None` encountered. +/// +/// See [`.while_some()`](../trait.Itertools.html#method.while_some) for more information. +#[derive(Clone, Debug)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct WhileSome { + iter: I, +} + +/// Create a new `WhileSome`. +pub fn while_some(iter: I) -> WhileSome { + WhileSome { iter } +} + +impl Iterator for WhileSome + where I: Iterator> +{ + type Item = A; + + fn next(&mut self) -> Option { + match self.iter.next() { + None | Some(None) => None, + Some(elt) => elt, + } + } + + fn size_hint(&self) -> (usize, Option) { + let sh = self.iter.size_hint(); + (0, sh.1) + } +} + +/// An iterator to iterate through all combinations in a `Clone`-able iterator that produces tuples +/// of a specific size. +/// +/// See [`.tuple_combinations()`](../trait.Itertools.html#method.tuple_combinations) for more +/// information. +#[derive(Clone, Debug)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct TupleCombinations + where I: Iterator, + T: HasCombination +{ + iter: T::Combination, + _mi: PhantomData, + _mt: PhantomData +} + +pub trait HasCombination: Sized { + type Combination: From + Iterator; +} + +/// Create a new `TupleCombinations` from a clonable iterator. +pub fn tuple_combinations(iter: I) -> TupleCombinations + where I: Iterator + Clone, + I::Item: Clone, + T: HasCombination, +{ + TupleCombinations { + iter: T::Combination::from(iter), + _mi: PhantomData, + _mt: PhantomData, + } +} + +impl Iterator for TupleCombinations + where I: Iterator, + T: HasCombination, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +#[derive(Clone, Debug)] +pub struct Tuple1Combination { + iter: I, +} + +impl From for Tuple1Combination { + fn from(iter: I) -> Self { + Tuple1Combination { iter } + } +} + +impl Iterator for Tuple1Combination { + type Item = (I::Item,); + + fn next(&mut self) -> Option { + self.iter.next().map(|x| (x,)) + } +} + +impl HasCombination for (I::Item,) { + type Combination = Tuple1Combination; +} + +macro_rules! impl_tuple_combination { + ($C:ident $P:ident ; $A:ident, $($I:ident),* ; $($X:ident)*) => ( + #[derive(Clone, Debug)] + pub struct $C { + item: Option, + iter: I, + c: $P, + } + + impl From for $C { + fn from(mut iter: I) -> Self { + $C { + item: iter.next(), + iter: iter.clone(), + c: $P::from(iter), + } + } + } + + impl From for $C> { + fn from(iter: I) -> Self { + let mut iter = iter.fuse(); + $C { + item: iter.next(), + iter: iter.clone(), + c: $P::from(iter), + } + } + } + + impl Iterator for $C + where I: Iterator + Clone, + I::Item: Clone + { + type Item = ($($I),*); + + fn next(&mut self) -> Option { + if let Some(($($X),*,)) = self.c.next() { + let z = self.item.clone().unwrap(); + Some((z, $($X),*)) + } else { + self.item = self.iter.next(); + self.item.clone().and_then(|z| { + self.c = $P::from(self.iter.clone()); + self.c.next().map(|($($X),*,)| (z, $($X),*)) + }) + } + } + } + + impl HasCombination for ($($I),*) + where I: Iterator + Clone, + I::Item: Clone + { + type Combination = $C>; + } + ) +} + +impl_tuple_combination!(Tuple2Combination Tuple1Combination ; A, A, A ; a); +impl_tuple_combination!(Tuple3Combination Tuple2Combination ; A, A, A, A ; a b); +impl_tuple_combination!(Tuple4Combination Tuple3Combination ; A, A, A, A, A; a b c); + +/// An iterator adapter to apply `Into` conversion to each element. +/// +/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information. +#[derive(Clone)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct MapInto { + iter: I, + _res: PhantomData R>, +} + +/// Create a new [`MapInto`](struct.MapInto.html) iterator. +pub fn map_into(iter: I) -> MapInto { + MapInto { + iter, + _res: PhantomData, + } +} + +impl Iterator for MapInto + where I: Iterator, + I::Item: Into, +{ + type Item = R; + + fn next(&mut self) -> Option { + self.iter + .next() + .map(|i| i.into()) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: Acc, mut fold_f: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, move |acc, v| fold_f(acc, v.into())) + } +} + +impl DoubleEndedIterator for MapInto + where I: DoubleEndedIterator, + I::Item: Into, +{ + fn next_back(&mut self) -> Option { + self.iter + .next_back() + .map(|i| i.into()) + } +} + +impl ExactSizeIterator for MapInto +where + I: ExactSizeIterator, + I::Item: Into, +{} + +/// An iterator adapter to apply a transformation within a nested `Result`. +/// +/// See [`.map_results()`](../trait.Itertools.html#method.map_results) for more information. +#[derive(Clone)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct MapResults { + iter: I, + f: F +} + +/// Create a new `MapResults` iterator. +pub fn map_results(iter: I, f: F) -> MapResults + where I: Iterator>, + F: FnMut(T) -> U, +{ + MapResults { + iter, + f, + } +} + +impl Iterator for MapResults + where I: Iterator>, + F: FnMut(T) -> U, +{ + type Item = Result; + + fn next(&mut self) -> Option { + self.iter.next().map(|v| v.map(&mut self.f)) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: Acc, mut fold_f: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, v| fold_f(acc, v.map(&mut f))) + } + + fn collect(self) -> C + where C: FromIterator + { + let mut f = self.f; + self.iter.map(move |v| v.map(&mut f)).collect() + } +} + +/// An iterator adapter to get the positions of each element that matches a predicate. +/// +/// See [`.positions()`](../trait.Itertools.html#method.positions) for more information. +#[derive(Clone)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct Positions { + iter: I, + f: F, + count: usize, +} + +/// Create a new `Positions` iterator. +pub fn positions(iter: I, f: F) -> Positions + where I: Iterator, + F: FnMut(I::Item) -> bool, +{ + Positions { + iter, + f, + count: 0 + } +} + +impl Iterator for Positions + where I: Iterator, + F: FnMut(I::Item) -> bool, +{ + type Item = usize; + + fn next(&mut self) -> Option { + while let Some(v) = self.iter.next() { + let i = self.count; + self.count = i + 1; + if (self.f)(v) { + return Some(i); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } +} + +impl DoubleEndedIterator for Positions + where I: DoubleEndedIterator + ExactSizeIterator, + F: FnMut(I::Item) -> bool, +{ + fn next_back(&mut self) -> Option { + while let Some(v) = self.iter.next_back() { + if (self.f)(v) { + return Some(self.count + self.iter.len()) + } + } + None + } +} + +/// An iterator adapter to apply a mutating function to each element before yielding it. +/// +/// See [`.update()`](../trait.Itertools.html#method.update) for more information. +#[derive(Clone)] +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct Update { + iter: I, + f: F, +} + +/// Create a new `Update` iterator. +pub fn update(iter: I, f: F) -> Update +where + I: Iterator, + F: FnMut(&mut I::Item), +{ + Update { iter, f } +} + +impl Iterator for Update +where + I: Iterator, + F: FnMut(&mut I::Item), +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + if let Some(mut v) = self.iter.next() { + (self.f)(&mut v); + Some(v) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: Acc, mut g: G) -> Acc + where G: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, mut v| { f(&mut v); g(acc, v) }) + } + + // if possible, re-use inner iterator specializations in collect + fn collect(self) -> C + where C: FromIterator + { + let mut f = self.f; + self.iter.map(move |mut v| { f(&mut v); v }).collect() + } +} + +impl ExactSizeIterator for Update +where + I: ExactSizeIterator, + F: FnMut(&mut I::Item), +{} + +impl DoubleEndedIterator for Update +where + I: DoubleEndedIterator, + F: FnMut(&mut I::Item), +{ + fn next_back(&mut self) -> Option { + if let Some(mut v) = self.iter.next_back() { + (self.f)(&mut v); + Some(v) + } else { + None + } + } +} diff --git a/src/rust/vendor/itertools/src/adaptors/multi_product.rs b/src/rust/vendor/itertools/src/adaptors/multi_product.rs new file mode 100644 index 000000000..4a31713ab --- /dev/null +++ b/src/rust/vendor/itertools/src/adaptors/multi_product.rs @@ -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`. +/// +/// 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(Vec>) + 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`. +pub fn multi_cartesian_product(iters: H) -> MultiProduct<::IntoIter> + where H: Iterator, + H::Item: IntoIterator, + ::IntoIter: Clone, + ::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 + where I: Iterator + Clone, + I::Item: Clone +{ + cur: Option, + 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 MultiProduct + 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], + 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 { + 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 MultiProductIter + 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 Iterator for MultiProduct + where I: Iterator + Clone, + I::Item: Clone +{ + type Item = Vec; + + fn next(&mut self) -> Option { + 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) { + // 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 { + 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 + } + } +} diff --git a/src/rust/vendor/itertools/src/combinations.rs b/src/rust/vendor/itertools/src/combinations.rs new file mode 100644 index 000000000..875951808 --- /dev/null +++ b/src/rust/vendor/itertools/src/combinations.rs @@ -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 { + indices: Vec, + pool: LazyBuffer, + first: bool, +} + +impl Clone for Combinations + where I: Clone + Iterator, + I::Item: Clone, +{ + clone_fields!(indices, pool, first); +} + +impl fmt::Debug for Combinations + 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(iter: I, k: usize) -> Combinations + where I: Iterator +{ + let mut pool: LazyBuffer = LazyBuffer::new(iter); + + for _ in 0..k { + if !pool.get_next() { + break; + } + } + + Combinations { + indices: (0..k).collect(), + pool, + first: true, + } +} + +impl Iterator for Combinations + where I: Iterator, + I::Item: Clone +{ + type Item = Vec; + fn next(&mut self) -> Option { + 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()) + } +} diff --git a/src/rust/vendor/itertools/src/combinations_with_replacement.rs b/src/rust/vendor/itertools/src/combinations_with_replacement.rs new file mode 100644 index 000000000..d51154521 --- /dev/null +++ b/src/rust/vendor/itertools/src/combinations_with_replacement.rs @@ -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 +where + I: Iterator, + I::Item: Clone, +{ + k: usize, + indices: Vec, + // The current known max index value. This increases as pool grows. + max_index: usize, + pool: LazyBuffer, + first: bool, +} + +impl fmt::Debug for CombinationsWithReplacement +where + I: Iterator + fmt::Debug, + I::Item: fmt::Debug + Clone, +{ + debug_fmt_fields!(Combinations, k, indices, max_index, pool, first); +} + +impl CombinationsWithReplacement +where + I: Iterator, + I::Item: Clone, +{ + /// Map the current mask over the pool to get an output combination + fn current(&self) -> Vec { + self.indices.iter().map(|i| self.pool[*i].clone()).collect() + } +} + +/// Create a new `CombinationsWithReplacement` from a clonable iterator. +pub fn combinations_with_replacement(iter: I, k: usize) -> CombinationsWithReplacement +where + I: Iterator, + I::Item: Clone, +{ + let indices: Vec = vec![0; k]; + let pool: LazyBuffer = LazyBuffer::new(iter); + + CombinationsWithReplacement { + k, + indices, + max_index: 0, + pool, + first: true, + } +} + +impl Iterator for CombinationsWithReplacement +where + I: Iterator, + I::Item: Clone, +{ + type Item = Vec; + fn next(&mut self) -> Option { + // 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, + } + } +} diff --git a/src/rust/vendor/itertools/src/concat_impl.rs b/src/rust/vendor/itertools/src/concat_impl.rs new file mode 100644 index 000000000..6048d18f6 --- /dev/null +++ b/src/rust/vendor/itertools/src/concat_impl.rs @@ -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(iterable: I) -> I::Item + where I: IntoIterator, + I::Item: Extend<<::Item as IntoIterator>::Item> + IntoIterator + Default +{ + iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_else(|| <_>::default()) +} diff --git a/src/rust/vendor/itertools/src/cons_tuples_impl.rs b/src/rust/vendor/itertools/src/cons_tuples_impl.rs new file mode 100644 index 000000000..3cdfe0d18 --- /dev/null +++ b/src/rust/vendor/itertools/src/cons_tuples_impl.rs @@ -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 Iterator for ConsTuples + where Iter: Iterator, + { + type Item = ($($B,)* X, ); + fn next(&mut self) -> Option { + self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, )) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + fn 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 DoubleEndedIterator for ConsTuples + where Iter: DoubleEndedIterator, + { + fn next_back(&mut self) -> Option { + 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 + where I: Iterator, +{ + iter: I, +} + +impl Clone for ConsTuples + where I: Clone + Iterator, +{ + clone_fields!(iter); +} + +/// Create an iterator that maps for example iterators of +/// `((A, B), C)` to `(A, B, C)`. +pub fn cons_tuples(iterable: I) -> ConsTuples + where I: Iterator +{ + ConsTuples { iter: iterable.into_iter() } +} diff --git a/src/rust/vendor/itertools/src/diff.rs b/src/rust/vendor/itertools/src/diff.rs new file mode 100644 index 000000000..c196d8d2f --- /dev/null +++ b/src/rust/vendor/itertools/src/diff.rs @@ -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 + 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, PutBack), + /// The total number of elements that were in `J` along with the remaining elements of `I`. + Shorter(usize, PutBack), + /// The total number of elements that were in `I` along with the remaining elements of `J`. + Longer(usize, PutBack), +} + +/// 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: I, j: J, is_equal: F) + -> Option> + 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))) +} diff --git a/src/rust/vendor/itertools/src/either_or_both.rs b/src/rust/vendor/itertools/src/either_or_both.rs new file mode 100644 index 000000000..a03a4f16e --- /dev/null +++ b/src/rust/vendor/itertools/src/either_or_both.rs @@ -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 { + /// 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 EitherOrBoth { + /// 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 { + 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 { + 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` 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` 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` to `EitherOrBoth`. + pub fn flip(self) -> EitherOrBoth { + 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(self, f: F) -> EitherOrBoth + 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(self, f: F) -> EitherOrBoth + 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(self, f: F, g: G) -> EitherOrBoth + 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(self, f: F) -> EitherOrBoth + where + F: FnOnce(A) -> EitherOrBoth, + { + 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(self, f: F) -> EitherOrBoth + where + F: FnOnce(B) -> EitherOrBoth, + { + match self { + Left(a) => Left(a), + Right(b) | Both(_, b) => f(b), + } + } +} + +impl EitherOrBoth { + /// Return either value of left, right, or the product of `f` applied where `Both` are present. + pub fn reduce(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 Into>> for EitherOrBoth { + fn into(self) -> Option> { + match self { + EitherOrBoth::Left(l) => Some(Either::Left(l)), + EitherOrBoth::Right(r) => Some(Either::Right(r)), + _ => None, + } + } +} diff --git a/src/rust/vendor/itertools/src/exactly_one_err.rs b/src/rust/vendor/itertools/src/exactly_one_err.rs new file mode 100644 index 000000000..e4925ffb7 --- /dev/null +++ b/src/rust/vendor/itertools/src/exactly_one_err.rs @@ -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 +where + I: Iterator, +{ + first_two: (Option, Option), + inner: I, +} + +impl ExactlyOneError +where + I: Iterator, +{ + /// Creates a new `ExactlyOneErr` iterator. + pub(crate) fn new(first_two: (Option, Option), inner: I) -> Self { + Self { first_two, inner } + } +} + +impl Iterator for ExactlyOneError +where + I: Iterator, +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + self.first_two + .0 + .take() + .or_else(|| self.first_two.1.take()) + .or_else(|| self.inner.next()) + } + + fn size_hint(&self) -> (usize, Option) { + 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 ExactSizeIterator for ExactlyOneError where I: ExactSizeIterator {} diff --git a/src/rust/vendor/itertools/src/format.rs b/src/rust/vendor/itertools/src/format.rs new file mode 100644 index 000000000..f72ed3917 --- /dev/null +++ b/src/rust/vendor/itertools/src/format.rs @@ -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>, +} + +/// 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>, +} + +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(&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} diff --git a/src/rust/vendor/itertools/src/free.rs b/src/rust/vendor/itertools/src/free.rs new file mode 100644 index 000000000..a6bc1bd1b --- /dev/null +++ b/src/rust/vendor/itertools/src/free.rs @@ -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 = ::std::vec::IntoIter; + +#[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(iterable: I) -> iter::Enumerate + 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(iterable: I) -> iter::Rev + 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: I, j: J) -> Zip + 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: I, j: J) -> iter::Chain<::IntoIter, ::IntoIter> + where I: IntoIterator, + J: IntoIterator +{ + 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 + where I: IntoIterator, + 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(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(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(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(iterable: I) -> Option + 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(iterable: I) -> Option + 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(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(iterable: I) -> VecIntoIter + where I: IntoIterator, + I::Item: Ord +{ + iterable.into_iter().sorted() +} + diff --git a/src/rust/vendor/itertools/src/group_map.rs b/src/rust/vendor/itertools/src/group_map.rs new file mode 100644 index 000000000..be9f8420d --- /dev/null +++ b/src/rust/vendor/itertools/src/group_map.rs @@ -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(iter: I) -> HashMap> + where I: Iterator, + K: Hash + Eq, +{ + let mut lookup = HashMap::new(); + + for (key, val) in iter { + lookup.entry(key).or_insert(Vec::new()).push(val); + } + + lookup +} \ No newline at end of file diff --git a/src/rust/vendor/itertools/src/groupbylazy.rs b/src/rust/vendor/itertools/src/groupbylazy.rs new file mode 100644 index 000000000..bf6e3c7a1 --- /dev/null +++ b/src/rust/vendor/itertools/src/groupbylazy.rs @@ -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 { + type Key; + fn call_mut(&mut self, arg: A) -> Self::Key; +} + +impl<'a, A, K, F: ?Sized> KeyFunction 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 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 + where I: Iterator +{ + key: F, + iter: I, + current_key: Option, + current_elt: Option, + /// 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>, + /// index of last group iter that was dropped, usize::MAX == none + dropped_group: usize, +} + +impl GroupInner + 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 { + /* + 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 { + // 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 { + 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 { + // 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) { + // 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 { + 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 GroupInner + 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 + where I: Iterator, +{ + inner: RefCell>, + // the group iterator's current index. Keep this in the main value + // so that simultaneous iterators all use the same state. + index: Cell, +} + +/// Create a new +pub fn new(iter: J, f: F) -> GroupBy + 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 GroupBy + where I: Iterator, +{ + /// `client`: Index of group that requests next element + fn step(&self, client: usize) -> Option + 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 + 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, +} + +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 { + 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, + index: usize, + first: Option, +} + +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 { + if let elt @ Some(..) = self.first.take() { + return elt; + } + self.parent.step(self.index) + } +} + +///// IntoChunks ///// + +/// Create a new +pub fn new_chunks(iter: J, size: usize) -> IntoChunks + 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 + where I: Iterator, +{ + inner: RefCell>, + // the chunk iterator's current index. Keep this in the main value + // so that simultaneous iterators all use the same state. + index: Cell, +} + + +impl IntoChunks + where I: Iterator, +{ + /// `client`: Index of chunk that requests next element + fn step(&self, client: usize) -> Option { + 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 + 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, +} + +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 { + 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, + index: usize, + first: Option, +} + +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 { + if let elt @ Some(..) = self.first.take() { + return elt; + } + self.parent.step(self.index) + } +} diff --git a/src/rust/vendor/itertools/src/impl_macros.rs b/src/rust/vendor/itertools/src/impl_macros.rs new file mode 100644 index 000000000..04ab8e177 --- /dev/null +++ b/src/rust/vendor/itertools/src/impl_macros.rs @@ -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(),)* + } + } + } +} diff --git a/src/rust/vendor/itertools/src/intersperse.rs b/src/rust/vendor/itertools/src/intersperse.rs new file mode 100644 index 000000000..057929927 --- /dev/null +++ b/src/rust/vendor/itertools/src/intersperse.rs @@ -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 + where I: Iterator +{ + element: I::Item, + iter: Fuse, + peek: Option, +} + +/// Create a new Intersperse iterator +pub fn intersperse(iter: I, elt: I::Item) -> Intersperse + where I: Iterator +{ + let mut iter = iter.fuse(); + Intersperse { + peek: iter.next(), + iter, + element: elt, + } +} + +impl Iterator for Intersperse + where I: Iterator, + I::Item: Clone +{ + type Item = I::Item; + #[inline] + fn next(&mut self) -> Option { + 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) { + // 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(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 + }) + } +} diff --git a/src/rust/vendor/itertools/src/kmerge_impl.rs b/src/rust/vendor/itertools/src/kmerge_impl.rs new file mode 100644 index 000000000..8f68aeb25 --- /dev/null +++ b/src/rust/vendor/itertools/src/kmerge_impl.rs @@ -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 + where I: Iterator +{ + head: I::Item, + tail: I, +} + +impl HeadTail + where I: Iterator +{ + /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty. + fn new(mut it: I) -> Option> { + 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 { + 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) { + size_hint::add_scalar(self.tail.size_hint(), 1) + } +} + +impl Clone for HeadTail + where I: Iterator + Clone, + I::Item: Clone +{ + clone_fields!(head, tail); +} + +/// Make `data` a heap (min-heap w.r.t the sorting). +fn heapify(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(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 = KMergeBy; + +pub trait KMergePredicate { + fn kmerge_pred(&mut self, a: &T, b: &T) -> bool; +} + +#[derive(Clone)] +pub struct KMergeByLt; + +impl KMergePredicate for KMergeByLt { + fn kmerge_pred(&mut self, a: &T, b: &T) -> bool { + a < b + } +} + +implbool> KMergePredicate 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(iterable: I) -> KMerge<::IntoIter> + where I: IntoIterator, + I::Item: 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 + where I: Iterator, +{ + heap: Vec>, + less_than: F, +} + +impl fmt::Debug for KMergeBy + 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(iterable: I, mut less_than: F) + -> KMergeBy<::IntoIter, F> + where I: IntoIterator, + I::Item: IntoIterator, + F: KMergePredicate<<::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 Clone for KMergeBy + where I: Iterator + Clone, + I::Item: Clone, + F: Clone, +{ + clone_fields!(heap, less_than); +} + +impl Iterator for KMergeBy + where I: Iterator, + F: KMergePredicate +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + 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) { + self.heap.iter() + .map(|i| i.size_hint()) + .fold1(size_hint::add) + .unwrap_or((0, Some(0))) + } +} diff --git a/src/rust/vendor/itertools/src/lazy_buffer.rs b/src/rust/vendor/itertools/src/lazy_buffer.rs new file mode 100644 index 000000000..01123d473 --- /dev/null +++ b/src/rust/vendor/itertools/src/lazy_buffer.rs @@ -0,0 +1,59 @@ +use std::ops::Index; + +#[derive(Debug, Clone)] +pub struct LazyBuffer { + pub it: I, + done: bool, + buffer: Vec, +} + +impl LazyBuffer +where + I: Iterator, +{ + pub fn new(it: I) -> LazyBuffer { + 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 Index for LazyBuffer +where + I: Iterator, + I::Item: Sized, + Vec: Index +{ + type Output = as Index>::Output; + + fn index(&self, _index: J) -> &Self::Output { + self.buffer.index(_index) + } +} diff --git a/src/rust/vendor/itertools/src/lib.rs b/src/rust/vendor/itertools/src/lib.rs new file mode 100644 index 000000000..b8daefda6 --- /dev/null +++ b/src/rust/vendor/itertools/src/lib.rs @@ -0,0 +1,2721 @@ +#![warn(missing_docs)] +#![crate_name="itertools"] +#![cfg_attr(not(feature = "use_std"), no_std)] + +//! Extra iterator adaptors, functions and macros. +//! +//! To extend [`Iterator`] with methods in this crate, import +//! the [`Itertools` trait](./trait.Itertools.html): +//! +//! ``` +//! use itertools::Itertools; +//! ``` +//! +//! Now, new methods like [`interleave`](./trait.Itertools.html#method.interleave) +//! are available on all iterators: +//! +//! ``` +//! use itertools::Itertools; +//! +//! let it = (1..3).interleave(vec![-1, -2]); +//! itertools::assert_equal(it, vec![1, -1, 2, -2]); +//! ``` +//! +//! Most iterator methods are also provided as functions (with the benefit +//! that they convert parameters using [`IntoIterator`]): +//! +//! ``` +//! use itertools::interleave; +//! +//! for elt in interleave(&[1, 2, 3], &[2, 3, 4]) { +//! /* loop body */ +//! } +//! ``` +//! +//! ## Crate Features +//! +//! - `use_std` +//! - Enabled by default. +//! - Disable to compile itertools using `#![no_std]`. This disables +//! any items that depend on collections (like `group_by`, `unique`, +//! `kmerge`, `join` and many more). +//! +//! ## Rust Version +//! +//! This version of itertools requires Rust 1.32 or later. +//! +//! [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html +#![doc(html_root_url="https://docs.rs/itertools/0.8/")] + +#[cfg(not(feature = "use_std"))] +extern crate core as std; + +pub use either::Either; + +#[cfg(feature = "use_std")] +use std::collections::HashMap; +use std::iter::{IntoIterator, once}; +use std::cmp::Ordering; +use std::fmt; +#[cfg(feature = "use_std")] +use std::hash::Hash; +#[cfg(feature = "use_std")] +use std::fmt::Write; +#[cfg(feature = "use_std")] +type VecIntoIter = ::std::vec::IntoIter; +#[cfg(feature = "use_std")] +use std::iter::FromIterator; + +#[macro_use] +mod impl_macros; + +// for compatibility with no std and macros +#[doc(hidden)] +pub use std::iter as __std_iter; + +/// The concrete iterator types. +pub mod structs { + pub use crate::adaptors::{ + Dedup, + DedupBy, + Interleave, + InterleaveShortest, + Product, + PutBack, + Batching, + MapInto, + MapResults, + Merge, + MergeBy, + TakeWhileRef, + WhileSome, + Coalesce, + TupleCombinations, + Positions, + Update, + }; + #[allow(deprecated)] + pub use crate::adaptors::Step; + #[cfg(feature = "use_std")] + pub use crate::adaptors::MultiProduct; + #[cfg(feature = "use_std")] + pub use crate::combinations::Combinations; + #[cfg(feature = "use_std")] + pub use crate::combinations_with_replacement::CombinationsWithReplacement; + pub use crate::cons_tuples_impl::ConsTuples; + pub use crate::exactly_one_err::ExactlyOneError; + pub use crate::format::{Format, FormatWith}; + #[cfg(feature = "use_std")] + pub use crate::groupbylazy::{IntoChunks, Chunk, Chunks, GroupBy, Group, Groups}; + pub use crate::intersperse::Intersperse; + #[cfg(feature = "use_std")] + pub use crate::kmerge_impl::{KMerge, KMergeBy}; + pub use crate::merge_join::MergeJoinBy; + #[cfg(feature = "use_std")] + pub use crate::multipeek_impl::MultiPeek; + pub use crate::pad_tail::PadUsing; + pub use crate::peeking_take_while::PeekingTakeWhile; + #[cfg(feature = "use_std")] + pub use crate::permutations::Permutations; + pub use crate::process_results_impl::ProcessResults; + #[cfg(feature = "use_std")] + pub use crate::put_back_n_impl::PutBackN; + #[cfg(feature = "use_std")] + pub use crate::rciter_impl::RcIter; + pub use crate::repeatn::RepeatN; + #[allow(deprecated)] + pub use crate::sources::{RepeatCall, Unfold, Iterate}; + #[cfg(feature = "use_std")] + pub use crate::tee::Tee; + pub use crate::tuple_impl::{TupleBuffer, TupleWindows, Tuples}; + #[cfg(feature = "use_std")] + pub use crate::unique_impl::{Unique, UniqueBy}; + pub use crate::with_position::WithPosition; + pub use crate::zip_eq_impl::ZipEq; + pub use crate::zip_longest::ZipLongest; + pub use crate::ziptuple::Zip; +} + +/// Traits helpful for using certain `Itertools` methods in generic contexts. +pub mod traits { + pub use crate::tuple_impl::HomogeneousTuple; +} + +#[allow(deprecated)] +pub use crate::structs::*; +pub use crate::concat_impl::concat; +pub use crate::cons_tuples_impl::cons_tuples; +pub use crate::diff::diff_with; +pub use crate::diff::Diff; +#[cfg(feature = "use_std")] +pub use crate::kmerge_impl::{kmerge_by}; +pub use crate::minmax::MinMaxResult; +pub use crate::peeking_take_while::PeekingNext; +pub use crate::process_results_impl::process_results; +pub use crate::repeatn::repeat_n; +#[allow(deprecated)] +pub use crate::sources::{repeat_call, unfold, iterate}; +pub use crate::with_position::Position; +pub use crate::ziptuple::multizip; +mod adaptors; +mod either_or_both; +pub use crate::either_or_both::EitherOrBoth; +#[doc(hidden)] +pub mod free; +#[doc(inline)] +pub use crate::free::*; +mod concat_impl; +mod cons_tuples_impl; +#[cfg(feature = "use_std")] +mod combinations; +#[cfg(feature = "use_std")] +mod combinations_with_replacement; +mod exactly_one_err; +mod diff; +mod format; +#[cfg(feature = "use_std")] +mod group_map; +#[cfg(feature = "use_std")] +mod groupbylazy; +mod intersperse; +#[cfg(feature = "use_std")] +mod kmerge_impl; +#[cfg(feature = "use_std")] +mod lazy_buffer; +mod merge_join; +mod minmax; +#[cfg(feature = "use_std")] +mod multipeek_impl; +mod pad_tail; +mod peeking_take_while; +#[cfg(feature = "use_std")] +mod permutations; +mod process_results_impl; +#[cfg(feature = "use_std")] +mod put_back_n_impl; +#[cfg(feature = "use_std")] +mod rciter_impl; +mod repeatn; +mod size_hint; +mod sources; +#[cfg(feature = "use_std")] +mod tee; +mod tuple_impl; +#[cfg(feature = "use_std")] +mod unique_impl; +mod with_position; +mod zip_eq_impl; +mod zip_longest; +mod ziptuple; + +#[macro_export] +/// Create an iterator over the “cartesian product” of iterators. +/// +/// Iterator element type is like `(A, B, ..., E)` if formed +/// from iterators `(I, J, ..., M)` with element types `I::Item = A`, `J::Item = B`, etc. +/// +/// ``` +/// # use itertools::iproduct; +/// # +/// # fn main() { +/// // Iterate over the coordinates of a 4 x 4 x 4 grid +/// // from (0, 0, 0), (0, 0, 1), .., (0, 1, 0), (0, 1, 1), .. etc until (3, 3, 3) +/// for (i, j, k) in iproduct!(0..4, 0..4, 0..4) { +/// // .. +/// } +/// # } +/// ``` +macro_rules! iproduct { + (@flatten $I:expr,) => ( + $I + ); + (@flatten $I:expr, $J:expr, $($K:expr,)*) => ( + iproduct!(@flatten $crate::cons_tuples(iproduct!($I, $J)), $($K,)*) + ); + ($I:expr) => ( + $crate::__std_iter::IntoIterator::into_iter($I) + ); + ($I:expr, $J:expr) => ( + $crate::Itertools::cartesian_product(iproduct!($I), iproduct!($J)) + ); + ($I:expr, $J:expr, $($K:expr),+) => ( + iproduct!(@flatten iproduct!($I, $J), $($K,)+) + ); +} + +#[macro_export] +/// Create an iterator running multiple iterators in lockstep. +/// +/// The `izip!` iterator yields elements until any subiterator +/// returns `None`. +/// +/// This is a version of the standard ``.zip()`` that's supporting more than +/// two iterators. The iterator element type is a tuple with one element +/// from each of the input iterators. Just like ``.zip()``, the iteration stops +/// when the shortest of the inputs reaches its end. +/// +/// **Note:** The result of this macro is in the general case an iterator +/// composed of repeated `.zip()` and a `.map()`; it has an anonymous type. +/// The special cases of one and two arguments produce the equivalent of +/// `$a.into_iter()` and `$a.into_iter().zip($b)` respectively. +/// +/// Prefer this macro `izip!()` over [`multizip`] for the performance benefits +/// of using the standard library `.zip()`. +/// +/// [`multizip`]: fn.multizip.html +/// +/// ``` +/// # use itertools::izip; +/// # +/// # fn main() { +/// +/// // 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 izip!(&mut results, 0..10, &inputs) { +/// *r = index * 10 + input; +/// } +/// +/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); +/// # } +/// ``` +macro_rules! izip { + // @closure creates a tuple-flattening closure for .map() call. usage: + // @closure partial_pattern => partial_tuple , rest , of , iterators + // eg. izip!( @closure ((a, b), c) => (a, b, c) , dd , ee ) + ( @closure $p:pat => $tup:expr ) => { + |$p| $tup + }; + + // The "b" identifier is a different identifier on each recursion level thanks to hygiene. + ( @closure $p:pat => ( $($tup:tt)* ) , $_iter:expr $( , $tail:expr )* ) => { + izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*) + }; + + // unary + ($first:expr $(,)*) => { + $crate::__std_iter::IntoIterator::into_iter($first) + }; + + // binary + ($first:expr, $second:expr $(,)*) => { + izip!($first) + .zip($second) + }; + + // n-ary where n > 2 + ( $first:expr $( , $rest:expr )* $(,)* ) => { + izip!($first) + $( + .zip($rest) + )* + .map( + izip!(@closure a => (a) $( , $rest )*) + ) + }; +} + +/// An [`Iterator`] blanket implementation that provides extra adaptors and +/// methods. +/// +/// This trait defines a number of methods. They are divided into two groups: +/// +/// * *Adaptors* take an iterator and parameter as input, and return +/// a new iterator value. These are listed first in the trait. An example +/// of an adaptor is [`.interleave()`](#method.interleave) +/// +/// * *Regular methods* are those that don't return iterators and instead +/// return a regular value of some other kind. +/// [`.next_tuple()`](#method.next_tuple) is an example and the first regular +/// method in the list. +/// +/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html +pub trait Itertools : Iterator { + // adaptors + + /// Alternate elements from two iterators until both have run out. + /// + /// Iterator element type is `Self::Item`. + /// + /// This iterator is *fused*. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = (1..7).interleave(vec![-1, -2]); + /// itertools::assert_equal(it, vec![1, -1, 2, -2, 3, 4, 5, 6]); + /// ``` + fn interleave(self, other: J) -> Interleave + where J: IntoIterator, + Self: Sized + { + interleave(self, other) + } + + /// Alternate elements from two iterators until at least one of them has run + /// out. + /// + /// Iterator element type is `Self::Item`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = (1..7).interleave_shortest(vec![-1, -2]); + /// itertools::assert_equal(it, vec![1, -1, 2, -2, 3]); + /// ``` + fn interleave_shortest(self, other: J) -> InterleaveShortest + where J: IntoIterator, + Self: Sized + { + adaptors::interleave_shortest(self, other.into_iter()) + } + + /// An iterator adaptor to insert a particular value + /// between each element of the adapted iterator. + /// + /// Iterator element type is `Self::Item`. + /// + /// This iterator is *fused*. + /// + /// ``` + /// use itertools::Itertools; + /// + /// itertools::assert_equal((0..3).intersperse(8), vec![0, 8, 1, 8, 2]); + /// ``` + fn intersperse(self, element: Self::Item) -> Intersperse + where Self: Sized, + Self::Item: Clone + { + intersperse::intersperse(self, element) + } + + /// Create an iterator which iterates over both this and the specified + /// iterator simultaneously, yielding pairs of two optional elements. + /// + /// This iterator is *fused*. + /// + /// As long as neither input iterator is exhausted yet, it yields two values + /// via `EitherOrBoth::Both`. + /// + /// When the parameter iterator is exhausted, it only yields a value from the + /// `self` iterator via `EitherOrBoth::Left`. + /// + /// When the `self` iterator is exhausted, it only yields a value from the + /// parameter iterator via `EitherOrBoth::Right`. + /// + /// When both iterators return `None`, all further invocations of `.next()` + /// will return `None`. + /// + /// Iterator element type is + /// [`EitherOrBoth`](enum.EitherOrBoth.html). + /// + /// ```rust + /// use itertools::EitherOrBoth::{Both, Right}; + /// use itertools::Itertools; + /// let it = (0..1).zip_longest(1..3); + /// itertools::assert_equal(it, vec![Both(0, 1), Right(2)]); + /// ``` + #[inline] + fn zip_longest(self, other: J) -> ZipLongest + where J: IntoIterator, + Self: Sized + { + zip_longest::zip_longest(self, other.into_iter()) + } + + /// Create an iterator which iterates over both this and the specified + /// iterator simultaneously, yielding pairs of elements. + /// + /// **Panics** if the iterators reach an end and they are not of equal + /// lengths. + #[inline] + fn zip_eq(self, other: J) -> ZipEq + where J: IntoIterator, + Self: Sized + { + zip_eq(self, other) + } + + /// A “meta iterator adaptor”. Its closure receives a reference to the + /// iterator and may pick off as many elements as it likes, to produce the + /// next iterator element. + /// + /// Iterator element type is `B`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// // An adaptor that gathers elements in pairs + /// let pit = (0..4).batching(|it| { + /// match it.next() { + /// None => None, + /// Some(x) => match it.next() { + /// None => None, + /// Some(y) => Some((x, y)), + /// } + /// } + /// }); + /// + /// itertools::assert_equal(pit, vec![(0, 1), (2, 3)]); + /// ``` + /// + fn batching(self, f: F) -> Batching + where F: FnMut(&mut Self) -> Option, + Self: Sized + { + adaptors::batching(self, f) + } + + /// Return an *iterable* that can group iterator elements. + /// Consecutive elements that map to the same key (“runs”), are assigned + /// to the same group. + /// + /// `GroupBy` is the storage for the lazy grouping operation. + /// + /// If the groups are consumed in order, or if each group's iterator 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. + /// + /// Iterator element type is `(K, Group)`: the group's key and the + /// group iterator. + /// + /// ``` + /// use itertools::Itertools; + /// + /// // group data into runs of larger than zero or not. + /// let data = vec![1, 3, -2, -2, 1, 0, 1, 2]; + /// // groups: |---->|------>|--------->| + /// + /// // Note: The `&` is significant here, `GroupBy` is iterable + /// // only by reference. You can also call `.into_iter()` explicitly. + /// let mut data_grouped = Vec::new(); + /// for (key, group) in &data.into_iter().group_by(|elt| *elt >= 0) { + /// data_grouped.push((key, group.collect())); + /// } + /// assert_eq!(data_grouped, vec![(true, vec![1, 3]), (false, vec![-2, -2]), (true, vec![1, 0, 1, 2])]); + /// ``` + #[cfg(feature = "use_std")] + fn group_by(self, key: F) -> GroupBy + where Self: Sized, + F: FnMut(&Self::Item) -> K, + K: PartialEq, + { + groupbylazy::new(self, key) + } + + /// Return an *iterable* that can chunk the iterator. + /// + /// Yield subiterators (chunks) that each yield a fixed number elements, + /// determined by `size`. The last chunk will be shorter if there aren't + /// enough elements. + /// + /// `IntoChunks` is based on `GroupBy`: it is iterable (implements + /// `IntoIterator`, **not** `Iterator`), and it only buffers if several + /// chunk iterators are alive at the same time. + /// + /// Iterator element type is `Chunk`, each chunk's iterator. + /// + /// **Panics** if `size` is 0. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = vec![1, 1, 2, -2, 6, 0, 3, 1]; + /// //chunk size=3 |------->|-------->|--->| + /// + /// // Note: The `&` is significant here, `IntoChunks` is iterable + /// // only by reference. You can also call `.into_iter()` explicitly. + /// for chunk in &data.into_iter().chunks(3) { + /// // Check that the sum of each chunk is 4. + /// assert_eq!(4, chunk.sum()); + /// } + /// ``` + #[cfg(feature = "use_std")] + fn chunks(self, size: usize) -> IntoChunks + where Self: Sized, + { + assert!(size != 0); + groupbylazy::new_chunks(self, size) + } + + /// Return an iterator over all contiguous windows producing tuples of + /// a specific size (up to 4). + /// + /// `tuple_windows` clones the iterator elements so that they can be + /// part of successive windows, this makes it most suited for iterators + /// of references and other values that are cheap to copy. + /// + /// ``` + /// use itertools::Itertools; + /// let mut v = Vec::new(); + /// for (a, b) in (1..5).tuple_windows() { + /// v.push((a, b)); + /// } + /// assert_eq!(v, vec![(1, 2), (2, 3), (3, 4)]); + /// + /// let mut it = (1..5).tuple_windows(); + /// assert_eq!(Some((1, 2, 3)), it.next()); + /// assert_eq!(Some((2, 3, 4)), it.next()); + /// assert_eq!(None, it.next()); + /// + /// // this requires a type hint + /// let it = (1..5).tuple_windows::<(_, _, _)>(); + /// itertools::assert_equal(it, vec![(1, 2, 3), (2, 3, 4)]); + /// + /// // you can also specify the complete type + /// use itertools::TupleWindows; + /// use std::ops::Range; + /// + /// let it: TupleWindows, (u32, u32, u32)> = (1..5).tuple_windows(); + /// itertools::assert_equal(it, vec![(1, 2, 3), (2, 3, 4)]); + /// ``` + fn tuple_windows(self) -> TupleWindows + where Self: Sized + Iterator, + T: traits::HomogeneousTuple, + T::Item: Clone + { + tuple_impl::tuple_windows(self) + } + + /// Return an iterator that groups the items in tuples of a specific size + /// (up to 4). + /// + /// See also the method [`.next_tuple()`](#method.next_tuple). + /// + /// ``` + /// use itertools::Itertools; + /// let mut v = Vec::new(); + /// for (a, b) in (1..5).tuples() { + /// v.push((a, b)); + /// } + /// assert_eq!(v, vec![(1, 2), (3, 4)]); + /// + /// let mut it = (1..7).tuples(); + /// assert_eq!(Some((1, 2, 3)), it.next()); + /// assert_eq!(Some((4, 5, 6)), it.next()); + /// assert_eq!(None, it.next()); + /// + /// // this requires a type hint + /// let it = (1..7).tuples::<(_, _, _)>(); + /// itertools::assert_equal(it, vec![(1, 2, 3), (4, 5, 6)]); + /// + /// // you can also specify the complete type + /// use itertools::Tuples; + /// use std::ops::Range; + /// + /// let it: Tuples, (u32, u32, u32)> = (1..7).tuples(); + /// itertools::assert_equal(it, vec![(1, 2, 3), (4, 5, 6)]); + /// ``` + /// + /// See also [`Tuples::into_buffer`](structs/struct.Tuples.html#method.into_buffer). + fn tuples(self) -> Tuples + where Self: Sized + Iterator, + T: traits::HomogeneousTuple + { + tuple_impl::tuples(self) + } + + /// Split into an iterator pair that both yield all elements from + /// the original iterator. + /// + /// **Note:** If the iterator is clonable, prefer using that instead + /// of using this method. It is likely to be more efficient. + /// + /// Iterator element type is `Self::Item`. + /// + /// ``` + /// use itertools::Itertools; + /// let xs = vec![0, 1, 2, 3]; + /// + /// let (mut t1, t2) = xs.into_iter().tee(); + /// itertools::assert_equal(t1.next(), Some(0)); + /// itertools::assert_equal(t2, 0..4); + /// itertools::assert_equal(t1, 1..4); + /// ``` + #[cfg(feature = "use_std")] + fn tee(self) -> (Tee, Tee) + where Self: Sized, + Self::Item: Clone + { + tee::new(self) + } + + /// Return an iterator adaptor that steps `n` elements in the base iterator + /// for each iteration. + /// + /// The iterator steps by yielding the next element from the base iterator, + /// then skipping forward `n - 1` elements. + /// + /// Iterator element type is `Self::Item`. + /// + /// **Panics** if the step is 0. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = (0..8).step(3); + /// itertools::assert_equal(it, vec![0, 3, 6]); + /// ``` + #[deprecated(note="Use std .step_by() instead", since="0.8")] + #[allow(deprecated)] + fn step(self, n: usize) -> Step + where Self: Sized + { + adaptors::step(self, n) + } + + /// Convert each item of the iterator using the `Into` trait. + /// + /// ```rust + /// use itertools::Itertools; + /// + /// (1i32..42i32).map_into::().collect_vec(); + /// ``` + fn map_into(self) -> MapInto + where Self: Sized, + Self::Item: Into, + { + adaptors::map_into(self) + } + + /// Return an iterator adaptor that applies the provided closure + /// to every `Result::Ok` value. `Result::Err` values are + /// unchanged. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let input = vec![Ok(41), Err(false), Ok(11)]; + /// let it = input.into_iter().map_results(|i| i + 1); + /// itertools::assert_equal(it, vec![Ok(42), Err(false), Ok(12)]); + /// ``` + fn map_results(self, f: F) -> MapResults + where Self: Iterator> + Sized, + F: FnMut(T) -> U, + { + adaptors::map_results(self, f) + } + + /// Return an iterator adaptor that merges the two base iterators in + /// ascending order. If both base iterators are sorted (ascending), the + /// result is sorted. + /// + /// Iterator element type is `Self::Item`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a = (0..11).step(3); + /// let b = (0..11).step(5); + /// let it = a.merge(b); + /// itertools::assert_equal(it, vec![0, 0, 3, 5, 6, 9, 10]); + /// ``` + fn merge(self, other: J) -> Merge + where Self: Sized, + Self::Item: PartialOrd, + J: IntoIterator + { + merge(self, other) + } + + /// Return an iterator adaptor that merges the two base iterators in order. + /// This is much like `.merge()` but allows for a custom ordering. + /// + /// This can be especially useful for sequences of tuples. + /// + /// Iterator element type is `Self::Item`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a = (0..).zip("bc".chars()); + /// let b = (0..).zip("ad".chars()); + /// let it = a.merge_by(b, |x, y| x.1 <= y.1); + /// itertools::assert_equal(it, vec![(0, 'a'), (0, 'b'), (1, 'c'), (1, 'd')]); + /// ``` + + fn merge_by(self, other: J, is_first: F) -> MergeBy + where Self: Sized, + J: IntoIterator, + F: FnMut(&Self::Item, &Self::Item) -> bool + { + adaptors::merge_by_new(self, other.into_iter(), is_first) + } + + /// Create an iterator that merges items from both this and the specified + /// iterator in ascending order. + /// + /// It chooses whether to pair elements based on the `Ordering` returned by the + /// specified compare function. At any point, inspecting the tip of the + /// iterators `I` and `J` as items `i` of type `I::Item` and `j` of type + /// `J::Item` respectively, the resulting iterator will: + /// + /// - Emit `EitherOrBoth::Left(i)` when `i < j`, + /// and remove `i` from its source iterator + /// - Emit `EitherOrBoth::Right(j)` when `i > j`, + /// and remove `j` from its source iterator + /// - Emit `EitherOrBoth::Both(i, j)` when `i == j`, + /// and remove both `i` and `j` from their respective source iterators + /// + /// ``` + /// use itertools::Itertools; + /// use itertools::EitherOrBoth::{Left, Right, Both}; + /// + /// let ki = (0..10).step(3); + /// let ku = (0..10).step(5); + /// let ki_ku = ki.merge_join_by(ku, |i, j| i.cmp(j)).map(|either| { + /// match either { + /// Left(_) => "Ki", + /// Right(_) => "Ku", + /// Both(_, _) => "KiKu" + /// } + /// }); + /// + /// itertools::assert_equal(ki_ku, vec!["KiKu", "Ki", "Ku", "Ki", "Ki"]); + /// ``` + #[inline] + fn merge_join_by(self, other: J, cmp_fn: F) -> MergeJoinBy + where J: IntoIterator, + F: FnMut(&Self::Item, &J::Item) -> std::cmp::Ordering, + Self: Sized + { + merge_join_by(self, other, cmp_fn) + } + + + /// Return an iterator adaptor that flattens an iterator of iterators by + /// merging them in ascending order. + /// + /// If all base iterators are sorted (ascending), the result is sorted. + /// + /// Iterator element type is `Self::Item`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a = (0..6).step(3); + /// let b = (1..6).step(3); + /// let c = (2..6).step(3); + /// let it = vec![a, b, c].into_iter().kmerge(); + /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5]); + /// ``` + #[cfg(feature = "use_std")] + fn kmerge(self) -> KMerge<::IntoIter> + where Self: Sized, + Self::Item: IntoIterator, + ::Item: PartialOrd, + { + kmerge(self) + } + + /// Return an iterator adaptor that flattens an iterator of iterators by + /// merging them according to the given closure. + /// + /// The closure `first` is called with two elements *a*, *b* and should + /// return `true` if *a* is ordered before *b*. + /// + /// If all base iterators are sorted according to `first`, the result is + /// sorted. + /// + /// Iterator element type is `Self::Item`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a = vec![-1f64, 2., 3., -5., 6., -7.]; + /// let b = vec![0., 2., -4.]; + /// let mut it = vec![a, b].into_iter().kmerge_by(|a, b| a.abs() < b.abs()); + /// assert_eq!(it.next(), Some(0.)); + /// assert_eq!(it.last(), Some(-7.)); + /// ``` + #[cfg(feature = "use_std")] + fn kmerge_by(self, first: F) + -> KMergeBy<::IntoIter, F> + where Self: Sized, + Self::Item: IntoIterator, + F: FnMut(&::Item, + &::Item) -> bool + { + kmerge_by(self, first) + } + + /// Return an iterator adaptor that iterates over the cartesian product of + /// the element sets of two iterators `self` and `J`. + /// + /// Iterator element type is `(Self::Item, J::Item)`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = (0..2).cartesian_product("αβ".chars()); + /// itertools::assert_equal(it, vec![(0, 'α'), (0, 'β'), (1, 'α'), (1, 'β')]); + /// ``` + fn cartesian_product(self, other: J) -> Product + where Self: Sized, + Self::Item: Clone, + J: IntoIterator, + J::IntoIter: Clone + { + adaptors::cartesian_product(self, other.into_iter()) + } + + /// Return an iterator adaptor that iterates over the cartesian product of + /// all subiterators returned by meta-iterator `self`. + /// + /// All provided iterators must yield the same `Item` type. To generate + /// the product of iterators yielding multiple types, use the + /// [`iproduct`](macro.iproduct.html) macro instead. + /// + /// + /// The iterator element type is `Vec`, where `T` is the iterator element + /// of the subiterators. + /// + /// ``` + /// use itertools::Itertools; + /// let mut multi_prod = (0..3).map(|i| (i * 2)..(i * 2 + 2)) + /// .multi_cartesian_product(); + /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 4])); + /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 5])); + /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 4])); + /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 5])); + /// assert_eq!(multi_prod.next(), Some(vec![1, 2, 4])); + /// assert_eq!(multi_prod.next(), Some(vec![1, 2, 5])); + /// assert_eq!(multi_prod.next(), Some(vec![1, 3, 4])); + /// assert_eq!(multi_prod.next(), Some(vec![1, 3, 5])); + /// assert_eq!(multi_prod.next(), None); + /// ``` + #[cfg(feature = "use_std")] + fn multi_cartesian_product(self) -> MultiProduct<::IntoIter> + where Self: Iterator + Sized, + Self::Item: IntoIterator, + ::IntoIter: Clone, + ::Item: Clone + { + adaptors::multi_cartesian_product(self) + } + + /// Return an iterator adaptor that uses the passed-in closure to + /// optionally merge together consecutive elements. + /// + /// The closure `f` is passed two elements, `previous` and `current` and may + /// return either (1) `Ok(combined)` to merge the two values or + /// (2) `Err((previous', current'))` to indicate they can't be merged. + /// In (2), the value `previous'` is emitted by the iterator. + /// Either (1) `combined` or (2) `current'` becomes the previous value + /// when coalesce continues with the next pair of elements to merge. The + /// value that remains at the end is also emitted by the iterator. + /// + /// Iterator element type is `Self::Item`. + /// + /// This iterator is *fused*. + /// + /// ``` + /// use itertools::Itertools; + /// + /// // sum same-sign runs together + /// let data = vec![-1., -2., -3., 3., 1., 0., -1.]; + /// itertools::assert_equal(data.into_iter().coalesce(|x, y| + /// if (x >= 0.) == (y >= 0.) { + /// Ok(x + y) + /// } else { + /// Err((x, y)) + /// }), + /// vec![-6., 4., -1.]); + /// ``` + fn coalesce(self, f: F) -> Coalesce + where Self: Sized, + F: FnMut(Self::Item, Self::Item) + -> Result + { + adaptors::coalesce(self, f) + } + + /// Remove duplicates from sections of consecutive identical elements. + /// If the iterator is sorted, all elements will be unique. + /// + /// Iterator element type is `Self::Item`. + /// + /// This iterator is *fused*. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = vec![1., 1., 2., 3., 3., 2., 2.]; + /// itertools::assert_equal(data.into_iter().dedup(), + /// vec![1., 2., 3., 2.]); + /// ``` + fn dedup(self) -> Dedup + where Self: Sized, + Self::Item: PartialEq, + { + adaptors::dedup(self) + } + + /// Remove duplicates from sections of consecutive identical elements, + /// determining equality using a comparison function. + /// If the iterator is sorted, all elements will be unique. + /// + /// Iterator element type is `Self::Item`. + /// + /// This iterator is *fused*. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = vec![(0, 1.), (1, 1.), (0, 2.), (0, 3.), (1, 3.), (1, 2.), (2, 2.)]; + /// itertools::assert_equal(data.into_iter().dedup_by(|x, y| x.1==y.1), + /// vec![(0, 1.), (0, 2.), (0, 3.), (1, 2.)]); + /// ``` + fn dedup_by(self, cmp: Cmp) -> DedupBy + where Self: Sized, + Cmp: FnMut(&Self::Item, &Self::Item)->bool, + { + adaptors::dedup_by(self, cmp) + } + + /// Return an iterator adaptor that filters out elements that have + /// already been produced once during the iteration. Duplicates + /// are detected using hash and equality. + /// + /// Clones of visited elements are stored in a hash set in the + /// iterator. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = vec![10, 20, 30, 20, 40, 10, 50]; + /// itertools::assert_equal(data.into_iter().unique(), + /// vec![10, 20, 30, 40, 50]); + /// ``` + #[cfg(feature = "use_std")] + fn unique(self) -> Unique + where Self: Sized, + Self::Item: Clone + Eq + Hash + { + unique_impl::unique(self) + } + + /// Return an iterator adaptor that filters out elements that have + /// already been produced once during the iteration. + /// + /// Duplicates are detected by comparing the key they map to + /// with the keying function `f` by hash and equality. + /// The keys are stored in a hash set in the iterator. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = vec!["a", "bb", "aa", "c", "ccc"]; + /// itertools::assert_equal(data.into_iter().unique_by(|s| s.len()), + /// vec!["a", "bb", "ccc"]); + /// ``` + #[cfg(feature = "use_std")] + fn unique_by(self, f: F) -> UniqueBy + where Self: Sized, + V: Eq + Hash, + F: FnMut(&Self::Item) -> V + { + unique_impl::unique_by(self, f) + } + + /// Return an iterator adaptor that borrows from this iterator and + /// takes items while the closure `accept` returns `true`. + /// + /// This adaptor can only be used on iterators that implement `PeekingNext` + /// like `.peekable()`, `put_back` and a few other collection iterators. + /// + /// The last and rejected element (first `false`) is still available when + /// `peeking_take_while` is done. + /// + /// + /// See also [`.take_while_ref()`](#method.take_while_ref) + /// which is a similar adaptor. + fn peeking_take_while(&mut self, accept: F) -> PeekingTakeWhile + where Self: Sized + PeekingNext, + F: FnMut(&Self::Item) -> bool, + { + peeking_take_while::peeking_take_while(self, accept) + } + + /// Return an iterator adaptor that borrows from a `Clone`-able iterator + /// to only pick off elements while the predicate `accept` returns `true`. + /// + /// It uses the `Clone` trait to restore the original iterator so that the + /// last and rejected element (first `false`) is still available when + /// `take_while_ref` is done. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let mut hexadecimals = "0123456789abcdef".chars(); + /// + /// let decimals = hexadecimals.take_while_ref(|c| c.is_numeric()) + /// .collect::(); + /// assert_eq!(decimals, "0123456789"); + /// assert_eq!(hexadecimals.next(), Some('a')); + /// + /// ``` + fn take_while_ref(&mut self, accept: F) -> TakeWhileRef + where Self: Clone, + F: FnMut(&Self::Item) -> bool + { + adaptors::take_while_ref(self, accept) + } + + /// Return an iterator adaptor that filters `Option` iterator elements + /// and produces `A`. Stops on the first `None` encountered. + /// + /// Iterator element type is `A`, the unwrapped element. + /// + /// ``` + /// use itertools::Itertools; + /// + /// // List all hexadecimal digits + /// itertools::assert_equal( + /// (0..).map(|i| std::char::from_digit(i, 16)).while_some(), + /// "0123456789abcdef".chars()); + /// + /// ``` + fn while_some(self) -> WhileSome + where Self: Sized + Iterator> + { + adaptors::while_some(self) + } + + /// Return an iterator adaptor that iterates over the combinations of the + /// elements from an iterator. + /// + /// Iterator element can be any homogeneous tuple of type `Self::Item` with + /// size up to 4. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let mut v = Vec::new(); + /// for (a, b) in (1..5).tuple_combinations() { + /// v.push((a, b)); + /// } + /// assert_eq!(v, vec![(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]); + /// + /// let mut it = (1..5).tuple_combinations(); + /// assert_eq!(Some((1, 2, 3)), it.next()); + /// assert_eq!(Some((1, 2, 4)), it.next()); + /// assert_eq!(Some((1, 3, 4)), it.next()); + /// assert_eq!(Some((2, 3, 4)), it.next()); + /// assert_eq!(None, it.next()); + /// + /// // this requires a type hint + /// let it = (1..5).tuple_combinations::<(_, _, _)>(); + /// itertools::assert_equal(it, vec![(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]); + /// + /// // you can also specify the complete type + /// use itertools::TupleCombinations; + /// use std::ops::Range; + /// + /// let it: TupleCombinations, (u32, u32, u32)> = (1..5).tuple_combinations(); + /// itertools::assert_equal(it, vec![(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]); + /// ``` + fn tuple_combinations(self) -> TupleCombinations + where Self: Sized + Clone, + Self::Item: Clone, + T: adaptors::HasCombination, + { + adaptors::tuple_combinations(self) + } + + /// Return an iterator adaptor that iterates over the `k`-length combinations of + /// the elements from an iterator. + /// + /// Iterator element type is `Vec`. The iterator produces a new Vec per iteration, + /// and clones the iterator elements. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = (1..5).combinations(3); + /// itertools::assert_equal(it, vec![ + /// vec![1, 2, 3], + /// vec![1, 2, 4], + /// vec![1, 3, 4], + /// vec![2, 3, 4], + /// ]); + /// ``` + /// + /// Note: Combinations does not take into account the equality of the iterated values. + /// ``` + /// use itertools::Itertools; + /// + /// let it = vec![1, 2, 2].into_iter().combinations(2); + /// itertools::assert_equal(it, vec![ + /// vec![1, 2], // Note: these are the same + /// vec![1, 2], // Note: these are the same + /// vec![2, 2], + /// ]); + /// ``` + #[cfg(feature = "use_std")] + fn combinations(self, k: usize) -> Combinations + where Self: Sized, + Self::Item: Clone + { + combinations::combinations(self, k) + } + + /// Return an iterator that iterates over the `k`-length combinations of + /// the elements from an iterator, with replacement. + /// + /// Iterator element type is `Vec`. The iterator produces a new Vec per iteration, + /// and clones the iterator elements. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = (1..4).combinations_with_replacement(2); + /// itertools::assert_equal(it, vec![ + /// vec![1, 1], + /// vec![1, 2], + /// vec![1, 3], + /// vec![2, 2], + /// vec![2, 3], + /// vec![3, 3], + /// ]); + /// ``` + #[cfg(feature = "use_std")] + fn combinations_with_replacement(self, k: usize) -> CombinationsWithReplacement + where + Self: Sized, + Self::Item: Clone, + { + combinations_with_replacement::combinations_with_replacement(self, k) + } + + /// Return an iterator adaptor that iterates over all k-permutations of the + /// elements from an iterator. + /// + /// Iterator element type is `Vec` with length `k`. The iterator + /// produces a new Vec per iteration, and clones the iterator elements. + /// + /// If `k` is greater than the length of the input iterator, the resultant + /// iterator adaptor will be empty. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let perms = (5..8).permutations(2); + /// itertools::assert_equal(perms, vec![ + /// vec![5, 6], + /// vec![5, 7], + /// vec![6, 5], + /// vec![6, 7], + /// vec![7, 5], + /// vec![7, 6], + /// ]); + /// ``` + /// + /// Note: Permutations does not take into account the equality of the iterated values. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = vec![2, 2].into_iter().permutations(2); + /// itertools::assert_equal(it, vec![ + /// vec![2, 2], // Note: these are the same + /// vec![2, 2], // Note: these are the same + /// ]); + /// ``` + /// + /// Note: The source iterator is collected lazily, and will not be + /// re-iterated if the permutations adaptor is completed and re-iterated. + #[cfg(feature = "use_std")] + fn permutations(self, k: usize) -> Permutations + where Self: Sized, + Self::Item: Clone + { + permutations::permutations(self, k) + } + + /// Return an iterator adaptor that pads the sequence to a minimum length of + /// `min` by filling missing elements using a closure `f`. + /// + /// Iterator element type is `Self::Item`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let it = (0..5).pad_using(10, |i| 2*i); + /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 10, 12, 14, 16, 18]); + /// + /// let it = (0..10).pad_using(5, |i| 2*i); + /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + /// + /// let it = (0..5).pad_using(10, |i| 2*i).rev(); + /// itertools::assert_equal(it, vec![18, 16, 14, 12, 10, 4, 3, 2, 1, 0]); + /// ``` + fn pad_using(self, min: usize, f: F) -> PadUsing + where Self: Sized, + F: FnMut(usize) -> Self::Item + { + pad_tail::pad_using(self, min, f) + } + + /// Return an iterator adaptor that wraps each element in a `Position` to + /// ease special-case handling of the first or last elements. + /// + /// Iterator element type is + /// [`Position`](enum.Position.html) + /// + /// ``` + /// use itertools::{Itertools, Position}; + /// + /// let it = (0..4).with_position(); + /// itertools::assert_equal(it, + /// vec![Position::First(0), + /// Position::Middle(1), + /// Position::Middle(2), + /// Position::Last(3)]); + /// + /// let it = (0..1).with_position(); + /// itertools::assert_equal(it, vec![Position::Only(0)]); + /// ``` + fn with_position(self) -> WithPosition + where Self: Sized, + { + with_position::with_position(self) + } + + /// Return an iterator adaptor that yields the indices of all elements + /// satisfying a predicate, counted from the start of the iterator. + /// + /// Equivalent to `iter.enumerate().filter(|(_, v)| predicate(v)).map(|(i, _)| i)`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = vec![1, 2, 3, 3, 4, 6, 7, 9]; + /// itertools::assert_equal(data.iter().positions(|v| v % 2 == 0), vec![1, 4, 5]); + /// + /// itertools::assert_equal(data.iter().positions(|v| v % 2 == 1).rev(), vec![7, 6, 3, 2, 0]); + /// ``` + fn positions

(self, predicate: P) -> Positions + where Self: Sized, + P: FnMut(Self::Item) -> bool, + { + adaptors::positions(self, predicate) + } + + /// Return an iterator adaptor that applies a mutating function + /// to each element before yielding it. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let input = vec![vec![1], vec![3, 2, 1]]; + /// let it = input.into_iter().update(|mut v| v.push(0)); + /// itertools::assert_equal(it, vec![vec![1, 0], vec![3, 2, 1, 0]]); + /// ``` + fn update(self, updater: F) -> Update + where Self: Sized, + F: FnMut(&mut Self::Item), + { + adaptors::update(self, updater) + } + + // non-adaptor methods + /// Advances the iterator and returns the next items grouped in a tuple of + /// a specific size (up to 4). + /// + /// If there are enough elements to be grouped in a tuple, then the tuple is + /// returned inside `Some`, otherwise `None` is returned. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let mut iter = 1..5; + /// + /// assert_eq!(Some((1, 2)), iter.next_tuple()); + /// ``` + fn next_tuple(&mut self) -> Option + where Self: Sized + Iterator, + T: traits::HomogeneousTuple + { + T::collect_from_iter_no_buf(self) + } + + /// Collects all items from the iterator into a tuple of a specific size + /// (up to 4). + /// + /// If the number of elements inside the iterator is **exactly** equal to + /// the tuple size, then the tuple is returned inside `Some`, otherwise + /// `None` is returned. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let iter = 1..3; + /// + /// if let Some((x, y)) = iter.collect_tuple() { + /// assert_eq!((x, y), (1, 2)) + /// } else { + /// panic!("Expected two elements") + /// } + /// ``` + fn collect_tuple(mut self) -> Option + where Self: Sized + Iterator, + T: traits::HomogeneousTuple + { + match self.next_tuple() { + elt @ Some(_) => match self.next() { + Some(_) => None, + None => elt, + }, + _ => None + } + } + + + /// Find the position and value of the first element satisfying a predicate. + /// + /// The iterator is not advanced past the first element found. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let text = "Hα"; + /// assert_eq!(text.chars().find_position(|ch| ch.is_lowercase()), Some((1, 'α'))); + /// ``` + fn find_position

(&mut self, mut pred: P) -> Option<(usize, Self::Item)> + where P: FnMut(&Self::Item) -> bool + { + let mut index = 0usize; + for elt in self { + if pred(&elt) { + return Some((index, elt)); + } + index += 1; + } + None + } + + /// Check whether all elements compare equal. + /// + /// Empty iterators are considered to have equal elements: + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = vec![1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5]; + /// assert!(!data.iter().all_equal()); + /// assert!(data[0..3].iter().all_equal()); + /// assert!(data[3..5].iter().all_equal()); + /// assert!(data[5..8].iter().all_equal()); + /// + /// let data : Option = None; + /// assert!(data.into_iter().all_equal()); + /// ``` + fn all_equal(&mut self) -> bool + where Self: Sized, + Self::Item: PartialEq, + { + match self.next() { + None => true, + Some(a) => self.all(|x| a == x), + } + } + + /// Consume the first `n` elements from the iterator eagerly, + /// and return the same iterator again. + /// + /// It works similarly to *.skip(* `n` *)* except it is eager and + /// preserves the iterator type. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let mut iter = "αβγ".chars().dropping(2); + /// itertools::assert_equal(iter, "γ".chars()); + /// ``` + /// + /// *Fusing notes: if the iterator is exhausted by dropping, + /// the result of calling `.next()` again depends on the iterator implementation.* + fn dropping(mut self, n: usize) -> Self + where Self: Sized + { + if n > 0 { + self.nth(n - 1); + } + self + } + + /// Consume the last `n` elements from the iterator eagerly, + /// and return the same iterator again. + /// + /// This is only possible on double ended iterators. `n` may be + /// larger than the number of elements. + /// + /// Note: This method is eager, dropping the back elements immediately and + /// preserves the iterator type. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let init = vec![0, 3, 6, 9].into_iter().dropping_back(1); + /// itertools::assert_equal(init, vec![0, 3, 6]); + /// ``` + fn dropping_back(mut self, n: usize) -> Self + where Self: Sized, + Self: DoubleEndedIterator + { + if n > 0 { + (&mut self).rev().nth(n - 1); + } + self + } + + /// Run the closure `f` eagerly on each element of the iterator. + /// + /// Consumes the iterator until its end. + /// + /// ``` + /// use std::sync::mpsc::channel; + /// use itertools::Itertools; + /// + /// let (tx, rx) = channel(); + /// + /// // use .foreach() to apply a function to each value -- sending it + /// (0..5).map(|x| x * 2 + 1).foreach(|x| { tx.send(x).unwrap(); } ); + /// + /// drop(tx); + /// + /// itertools::assert_equal(rx.iter(), vec![1, 3, 5, 7, 9]); + /// ``` + #[deprecated(note="Use .for_each() instead", since="0.8")] + fn foreach(self, f: F) + where F: FnMut(Self::Item), + Self: Sized, + { + self.for_each(f) + } + + /// Combine all an iterator's elements into one element by using `Extend`. + /// + /// 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::Itertools; + /// + /// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]]; + /// assert_eq!(input.into_iter().concat(), + /// vec![1, 2, 3, 4, 5, 6]); + /// ``` + fn concat(self) -> Self::Item + where Self: Sized, + Self::Item: Extend<<::Item as IntoIterator>::Item> + IntoIterator + Default + { + concat(self) + } + + /// `.collect_vec()` is simply a type specialization of `.collect()`, + /// for convenience. + #[cfg(feature = "use_std")] + fn collect_vec(self) -> Vec + where Self: Sized + { + self.collect() + } + + /// `.try_collect()` is more convenient way of writing + /// `.collect::>()` + /// + /// # Example + /// + /// ``` + /// use std::{fs, io}; + /// use itertools::Itertools; + /// + /// fn process_dir_entries(entries: &[fs::DirEntry]) { + /// // ... + /// } + /// + /// fn do_stuff() -> std::io::Result<()> { + /// let entries: Vec<_> = fs::read_dir(".")?.try_collect()?; + /// process_dir_entries(&entries); + /// + /// Ok(()) + /// } + /// ``` + #[cfg(feature = "use_std")] + fn try_collect(self) -> Result + where + Self: Sized + Iterator>, + Result: FromIterator>, + { + self.collect() + } + + /// Assign to each reference in `self` from the `from` iterator, + /// stopping at the shortest of the two iterators. + /// + /// The `from` iterator is queried for its next element before the `self` + /// iterator, and if either is exhausted the method is done. + /// + /// Return the number of elements written. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let mut xs = [0; 4]; + /// xs.iter_mut().set_from(1..); + /// assert_eq!(xs, [1, 2, 3, 4]); + /// ``` + #[inline] + fn set_from<'a, A: 'a, J>(&mut self, from: J) -> usize + where Self: Iterator, + J: IntoIterator + { + let mut count = 0; + for elt in from { + match self.next() { + None => break, + Some(ptr) => *ptr = elt, + } + count += 1; + } + count + } + + /// Combine all iterator elements into one String, separated by `sep`. + /// + /// Use the `Display` implementation of each element. + /// + /// ``` + /// use itertools::Itertools; + /// + /// assert_eq!(["a", "b", "c"].iter().join(", "), "a, b, c"); + /// assert_eq!([1, 2, 3].iter().join(", "), "1, 2, 3"); + /// ``` + #[cfg(feature = "use_std")] + fn join(&mut self, sep: &str) -> String + where Self::Item: std::fmt::Display + { + match self.next() { + None => String::new(), + Some(first_elt) => { + // estimate lower bound of capacity needed + let (lower, _) = self.size_hint(); + let mut result = String::with_capacity(sep.len() * lower); + write!(&mut result, "{}", first_elt).unwrap(); + for elt in self { + result.push_str(sep); + write!(&mut result, "{}", elt).unwrap(); + } + result + } + } + } + + /// Format all iterator elements, separated by `sep`. + /// + /// All elements are formatted (any formatting trait) + /// with `sep` inserted between each element. + /// + /// **Panics** if the formatter helper is formatted more than once. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = [1.1, 2.71828, -3.]; + /// assert_eq!( + /// format!("{:.2}", data.iter().format(", ")), + /// "1.10, 2.72, -3.00"); + /// ``` + fn format(self, sep: &str) -> Format + where Self: Sized, + { + format::new_format_default(self, sep) + } + + /// Format all iterator elements, separated by `sep`. + /// + /// This is a customizable version of `.format()`. + /// + /// The supplied closure `format` is called once per iterator element, + /// with two arguments: the element and a callback that takes a + /// `&Display` value, i.e. any reference to type that implements `Display`. + /// + /// Using `&format_args!(...)` is the most versatile way to apply custom + /// element formatting. The callback can be called multiple times if needed. + /// + /// **Panics** if the formatter helper is formatted more than once. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = [1.1, 2.71828, -3.]; + /// let data_formatter = data.iter().format_with(", ", |elt, f| f(&format_args!("{:.2}", elt))); + /// assert_eq!(format!("{}", data_formatter), + /// "1.10, 2.72, -3.00"); + /// + /// // .format_with() is recursively composable + /// let matrix = [[1., 2., 3.], + /// [4., 5., 6.]]; + /// let matrix_formatter = matrix.iter().format_with("\n", |row, f| { + /// f(&row.iter().format_with(", ", |elt, g| g(&elt))) + /// }); + /// assert_eq!(format!("{}", matrix_formatter), + /// "1, 2, 3\n4, 5, 6"); + /// + /// + /// ``` + fn format_with(self, sep: &str, format: F) -> FormatWith + where Self: Sized, + F: FnMut(Self::Item, &mut dyn FnMut(&dyn fmt::Display) -> fmt::Result) -> fmt::Result, + { + format::new_format(self, sep, format) + } + + /// Fold `Result` values from an iterator. + /// + /// Only `Ok` values are folded. If no error is encountered, the folded + /// value is returned inside `Ok`. Otherwise, the operation terminates + /// and returns the first `Err` value it encounters. No iterator elements are + /// consumed after the first error. + /// + /// The first accumulator value is the `start` parameter. + /// Each iteration passes the accumulator value and the next value inside `Ok` + /// to the fold function `f` and its return value becomes the new accumulator value. + /// + /// For example the sequence *Ok(1), Ok(2), Ok(3)* will result in a + /// computation like this: + /// + /// ```ignore + /// let mut accum = start; + /// accum = f(accum, 1); + /// accum = f(accum, 2); + /// accum = f(accum, 3); + /// ``` + /// + /// With a `start` value of 0 and an addition as folding function, + /// this effectively results in *((0 + 1) + 2) + 3* + /// + /// ``` + /// use std::ops::Add; + /// use itertools::Itertools; + /// + /// let values = [1, 2, -2, -1, 2, 1]; + /// assert_eq!( + /// values.iter() + /// .map(Ok::<_, ()>) + /// .fold_results(0, Add::add), + /// Ok(3) + /// ); + /// assert!( + /// values.iter() + /// .map(|&x| if x >= 0 { Ok(x) } else { Err("Negative number") }) + /// .fold_results(0, Add::add) + /// .is_err() + /// ); + /// ``` + fn fold_results(&mut self, mut start: B, mut f: F) -> Result + where Self: Iterator>, + F: FnMut(B, A) -> B + { + for elt in self { + match elt { + Ok(v) => start = f(start, v), + Err(u) => return Err(u), + } + } + Ok(start) + } + + /// Fold `Option` values from an iterator. + /// + /// Only `Some` values are folded. If no `None` is encountered, the folded + /// value is returned inside `Some`. Otherwise, the operation terminates + /// and returns `None`. No iterator elements are consumed after the `None`. + /// + /// This is the `Option` equivalent to `fold_results`. + /// + /// ``` + /// use std::ops::Add; + /// use itertools::Itertools; + /// + /// let mut values = vec![Some(1), Some(2), Some(-2)].into_iter(); + /// assert_eq!(values.fold_options(5, Add::add), Some(5 + 1 + 2 - 2)); + /// + /// let mut more_values = vec![Some(2), None, Some(0)].into_iter(); + /// assert!(more_values.fold_options(0, Add::add).is_none()); + /// assert_eq!(more_values.next().unwrap(), Some(0)); + /// ``` + fn fold_options(&mut self, mut start: B, mut f: F) -> Option + where Self: Iterator>, + F: FnMut(B, A) -> B + { + for elt in self { + match elt { + Some(v) => start = f(start, v), + None => return None, + } + } + Some(start) + } + + /// Accumulator of the elements in the iterator. + /// + /// Like `.fold()`, without a base case. If the iterator is + /// empty, return `None`. With just one element, return it. + /// Otherwise elements are accumulated in sequence using the closure `f`. + /// + /// ``` + /// use itertools::Itertools; + /// + /// assert_eq!((0..10).fold1(|x, y| x + y).unwrap_or(0), 45); + /// assert_eq!((0..0).fold1(|x, y| x * y), None); + /// ``` + fn fold1(mut self, f: F) -> Option + where F: FnMut(Self::Item, Self::Item) -> Self::Item, + Self: Sized, + { + self.next().map(move |x| self.fold(x, f)) + } + + /// Accumulate the elements in the iterator in a tree-like manner. + /// + /// You can think of it as, while there's more than one item, repeatedly + /// combining adjacent items. It does so in bottom-up-merge-sort order, + /// however, so that it needs only logarithmic stack space. + /// + /// This produces a call tree like the following (where the calls under + /// an item are done after reading that item): + /// + /// ```text + /// 1 2 3 4 5 6 7 + /// │ │ │ │ │ │ │ + /// └─f └─f └─f │ + /// │ │ │ │ + /// └───f └─f + /// │ │ + /// └─────f + /// ``` + /// + /// Which, for non-associative functions, will typically produce a different + /// result than the linear call tree used by `fold1`: + /// + /// ```text + /// 1 2 3 4 5 6 7 + /// │ │ │ │ │ │ │ + /// └─f─f─f─f─f─f + /// ``` + /// + /// If `f` is associative, prefer the normal `fold1` instead. + /// + /// ``` + /// use itertools::Itertools; + /// + /// // The same tree as above + /// let num_strings = (1..8).map(|x| x.to_string()); + /// assert_eq!(num_strings.tree_fold1(|x, y| format!("f({}, {})", x, y)), + /// Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))"))); + /// + /// // Like fold1, an empty iterator produces None + /// assert_eq!((0..0).tree_fold1(|x, y| x * y), None); + /// + /// // tree_fold1 matches fold1 for associative operations... + /// assert_eq!((0..10).tree_fold1(|x, y| x + y), + /// (0..10).fold1(|x, y| x + y)); + /// // ...but not for non-associative ones + /// assert_ne!((0..10).tree_fold1(|x, y| x - y), + /// (0..10).fold1(|x, y| x - y)); + /// ``` + fn tree_fold1(mut self, mut f: F) -> Option + where F: FnMut(Self::Item, Self::Item) -> Self::Item, + Self: Sized, + { + type State = Result>; + + fn inner0(it: &mut II, f: &mut FF) -> State + where + II: Iterator, + FF: FnMut(T, T) -> T + { + // This function could be replaced with `it.next().ok_or(None)`, + // but half the useful tree_fold1 work is combining adjacent items, + // so put that in a form that LLVM is more likely to optimize well. + + let a = + if let Some(v) = it.next() { v } + else { return Err(None) }; + let b = + if let Some(v) = it.next() { v } + else { return Err(Some(a)) }; + Ok(f(a, b)) + } + + fn inner(stop: usize, it: &mut II, f: &mut FF) -> State + where + II: Iterator, + FF: FnMut(T, T) -> T + { + let mut x = inner0(it, f)?; + for height in 0..stop { + // Try to get another tree the same size with which to combine it, + // creating a new tree that's twice as big for next time around. + let next = + if height == 0 { + inner0(it, f) + } else { + inner(height, it, f) + }; + match next { + Ok(y) => x = f(x, y), + + // If we ran out of items, combine whatever we did manage + // to get. It's better combined with the current value + // than something in a parent frame, because the tree in + // the parent is always as least as big as this one. + Err(None) => return Err(Some(x)), + Err(Some(y)) => return Err(Some(f(x, y))), + } + } + Ok(x) + } + + match inner(usize::max_value(), &mut self, &mut f) { + Err(x) => x, + _ => unreachable!(), + } + } + + /// An iterator method that applies a function, producing a single, final value. + /// + /// `fold_while()` is basically equivalent to `fold()` but with additional support for + /// early exit via short-circuiting. + /// + /// ``` + /// use itertools::Itertools; + /// use itertools::FoldWhile::{Continue, Done}; + /// + /// let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + /// + /// let mut result = 0; + /// + /// // for loop: + /// for i in &numbers { + /// if *i > 5 { + /// break; + /// } + /// result = result + i; + /// } + /// + /// // fold: + /// let result2 = numbers.iter().fold(0, |acc, x| { + /// if *x > 5 { acc } else { acc + x } + /// }); + /// + /// // fold_while: + /// let result3 = numbers.iter().fold_while(0, |acc, x| { + /// if *x > 5 { Done(acc) } else { Continue(acc + x) } + /// }).into_inner(); + /// + /// // they're the same + /// assert_eq!(result, result2); + /// assert_eq!(result2, result3); + /// ``` + /// + /// The big difference between the computations of `result2` and `result3` is that while + /// `fold()` called the provided closure for every item of the callee iterator, + /// `fold_while()` actually stopped iterating as soon as it encountered `Fold::Done(_)`. + #[deprecated(note="Use .try_fold() instead", since="0.8")] + fn fold_while(&mut self, init: B, mut f: F) -> FoldWhile + where Self: Sized, + F: FnMut(B, Self::Item) -> FoldWhile + { + let mut acc = init; + while let Some(item) = self.next() { + match f(acc, item) { + FoldWhile::Continue(res) => acc = res, + res @ FoldWhile::Done(_) => return res, + } + } + FoldWhile::Continue(acc) + } + + /// Iterate over the entire iterator and add all the elements. + /// + /// An empty iterator returns `None`, otherwise `Some(sum)`. + /// + /// # Panics + /// + /// When calling `sum1()` and a primitive integer type is being returned, this + /// method will panic if the computation overflows and debug assertions are + /// enabled. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let empty_sum = (1..1).sum1::(); + /// assert_eq!(empty_sum, None); + /// + /// let nonempty_sum = (1..11).sum1::(); + /// assert_eq!(nonempty_sum, Some(55)); + /// ``` + fn sum1(mut self) -> Option + where Self: Sized, + S: std::iter::Sum, + { + self.next() + .map(|first| once(first).chain(self).sum()) + } + + /// Iterate over the entire iterator and multiply all the elements. + /// + /// An empty iterator returns `None`, otherwise `Some(product)`. + /// + /// # Panics + /// + /// When calling `product1()` and a primitive integer type is being returned, + /// method will panic if the computation overflows and debug assertions are + /// enabled. + /// + /// # Examples + /// ``` + /// use itertools::Itertools; + /// + /// let empty_product = (1..1).product1::(); + /// assert_eq!(empty_product, None); + /// + /// let nonempty_product = (1..11).product1::(); + /// assert_eq!(nonempty_product, Some(3628800)); + /// ``` + fn product1

(mut self) -> Option

+ where Self: Sized, + P: std::iter::Product, + { + self.next() + .map(|first| once(first).chain(self).product()) + } + + + /// Sort all iterator elements into a new iterator in ascending order. + /// + /// **Note:** This consumes the entire iterator, uses the + /// `slice::sort()` method and returns the result as a new + /// iterator that owns its elements. + /// + /// The sorted iterator, if directly collected to a `Vec`, is converted + /// without any extra copying or allocation cost. + /// + /// ``` + /// use itertools::Itertools; + /// + /// // sort the letters of the text in ascending order + /// let text = "bdacfe"; + /// itertools::assert_equal(text.chars().sorted(), + /// "abcdef".chars()); + /// ``` + #[cfg(feature = "use_std")] + fn sorted(self) -> VecIntoIter + where Self: Sized, + Self::Item: Ord + { + // Use .sort() directly since it is not quite identical with + // .sort_by(Ord::cmp) + let mut v = Vec::from_iter(self); + v.sort(); + v.into_iter() + } + + /// Sort all iterator elements into a new iterator in ascending order. + /// + /// **Note:** This consumes the entire iterator, uses the + /// `slice::sort_by()` method and returns the result as a new + /// iterator that owns its elements. + /// + /// The sorted iterator, if directly collected to a `Vec`, is converted + /// without any extra copying or allocation cost. + /// + /// ``` + /// use itertools::Itertools; + /// + /// // sort people in descending order by age + /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; + /// + /// let oldest_people_first = people + /// .into_iter() + /// .sorted_by(|a, b| Ord::cmp(&b.1, &a.1)) + /// .map(|(person, _age)| person); + /// + /// itertools::assert_equal(oldest_people_first, + /// vec!["Jill", "Jack", "Jane", "John"]); + /// ``` + #[cfg(feature = "use_std")] + fn sorted_by(self, cmp: F) -> VecIntoIter + where Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + let mut v = Vec::from_iter(self); + v.sort_by(cmp); + v.into_iter() + } + + /// Sort all iterator elements into a new iterator in ascending order. + /// + /// **Note:** This consumes the entire iterator, uses the + /// `slice::sort_by_key()` method and returns the result as a new + /// iterator that owns its elements. + /// + /// The sorted iterator, if directly collected to a `Vec`, is converted + /// without any extra copying or allocation cost. + /// + /// ``` + /// use itertools::Itertools; + /// + /// // sort people in descending order by age + /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; + /// + /// let oldest_people_first = people + /// .into_iter() + /// .sorted_by_key(|x| -x.1) + /// .map(|(person, _age)| person); + /// + /// itertools::assert_equal(oldest_people_first, + /// vec!["Jill", "Jack", "Jane", "John"]); + /// ``` + #[cfg(feature = "use_std")] + fn sorted_by_key(self, f: F) -> VecIntoIter + where Self: Sized, + K: Ord, + F: FnMut(&Self::Item) -> K, + { + let mut v = Vec::from_iter(self); + v.sort_by_key(f); + v.into_iter() + } + + /// Collect all iterator elements into one of two + /// partitions. Unlike `Iterator::partition`, each partition may + /// have a distinct type. + /// + /// ``` + /// use itertools::{Itertools, Either}; + /// + /// let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)]; + /// + /// let (successes, failures): (Vec<_>, Vec<_>) = successes_and_failures + /// .into_iter() + /// .partition_map(|r| { + /// match r { + /// Ok(v) => Either::Left(v), + /// Err(v) => Either::Right(v), + /// } + /// }); + /// + /// assert_eq!(successes, [1, 2]); + /// assert_eq!(failures, [false, true]); + /// ``` + fn partition_map(self, mut predicate: F) -> (A, B) + where Self: Sized, + F: FnMut(Self::Item) -> Either, + A: Default + Extend, + B: Default + Extend, + { + let mut left = A::default(); + let mut right = B::default(); + + self.for_each(|val| match predicate(val) { + Either::Left(v) => left.extend(Some(v)), + Either::Right(v) => right.extend(Some(v)), + }); + + (left, right) + } + + /// Return a `HashMap` of keys mapped to `Vec`s of values. Keys and values + /// are taken from `(Key, Value)` tuple pairs yielded by the input iterator. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)]; + /// let lookup = data.into_iter().into_group_map(); + /// + /// assert_eq!(lookup[&0], vec![10, 20]); + /// assert_eq!(lookup.get(&1), None); + /// assert_eq!(lookup[&2], vec![12, 42]); + /// assert_eq!(lookup[&3], vec![13, 33]); + /// ``` + #[cfg(feature = "use_std")] + fn into_group_map(self) -> HashMap> + where Self: Iterator + Sized, + K: Hash + Eq, + { + group_map::into_group_map(self) + } + + /// Return the minimum and maximum elements in the iterator. + /// + /// The return type `MinMaxResult` is an enum of three variants: + /// + /// - `NoElements` if the iterator is empty. + /// - `OneElement(x)` if the iterator has exactly one element. + /// - `MinMax(x, y)` is returned otherwise, where `x <= y`. Two + /// values are equal if and only if there is more than one + /// element in the iterator and all elements are equal. + /// + /// On an iterator of length `n`, `minmax` does `1.5 * n` comparisons, + /// and so is faster than calling `min` and `max` separately which does + /// `2 * n` comparisons. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().minmax(), NoElements); + /// + /// let a = [1]; + /// assert_eq!(a.iter().minmax(), OneElement(&1)); + /// + /// let a = [1, 2, 3, 4, 5]; + /// assert_eq!(a.iter().minmax(), MinMax(&1, &5)); + /// + /// let a = [1, 1, 1, 1]; + /// assert_eq!(a.iter().minmax(), MinMax(&1, &1)); + /// ``` + /// + /// The elements can be floats but no particular result is guaranteed + /// if an element is NaN. + fn minmax(self) -> MinMaxResult + where Self: Sized, Self::Item: PartialOrd + { + minmax::minmax_impl(self, |_| (), |x, y, _, _| x < y) + } + + /// Return the minimum and maximum element of an iterator, as determined by + /// the specified function. + /// + /// The return value is a variant of `MinMaxResult` like for `minmax()`. + /// + /// For the minimum, the first minimal element is returned. For the maximum, + /// the last maximal element wins. This matches the behavior of the standard + /// `Iterator::min()` and `Iterator::max()` methods. + /// + /// The keys can be floats but no particular result is guaranteed + /// if a key is NaN. + fn minmax_by_key(self, key: F) -> MinMaxResult + where Self: Sized, K: PartialOrd, F: FnMut(&Self::Item) -> K + { + minmax::minmax_impl(self, key, |_, _, xk, yk| xk < yk) + } + + /// Return the minimum and maximum element of an iterator, as determined by + /// the specified comparison function. + /// + /// The return value is a variant of `MinMaxResult` like for `minmax()`. + /// + /// For the minimum, the first minimal element is returned. For the maximum, + /// the last maximal element wins. This matches the behavior of the standard + /// `Iterator::min()` and `Iterator::max()` methods. + fn minmax_by(self, mut compare: F) -> MinMaxResult + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering + { + minmax::minmax_impl( + self, + |_| (), + |x, y, _, _| Ordering::Less == compare(x, y) + ) + } + + /// Return the position of the maximum element in the iterator. + /// + /// If several elements are equally maximum, the position of the + /// last of them is returned. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().position_max(), None); + /// + /// let a = [-3, 0, 1, 5, -10]; + /// assert_eq!(a.iter().position_max(), Some(3)); + /// + /// let a = [1, 1, -1, -1]; + /// assert_eq!(a.iter().position_max(), Some(1)); + /// ``` + fn position_max(self) -> Option + where Self: Sized, Self::Item: Ord + { + self.enumerate() + .max_by(|x, y| Ord::cmp(&x.1, &y.1)) + .map(|x| x.0) + } + + /// Return the position of the maximum element in the iterator, as + /// determined by the specified function. + /// + /// If several elements are equally maximum, the position of the + /// last of them is returned. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().position_max_by_key(|x| x.abs()), None); + /// + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(a.iter().position_max_by_key(|x| x.abs()), Some(4)); + /// + /// let a = [1_i32, 1, -1, -1]; + /// assert_eq!(a.iter().position_max_by_key(|x| x.abs()), Some(3)); + /// ``` + fn position_max_by_key(self, mut key: F) -> Option + where Self: Sized, K: Ord, F: FnMut(&Self::Item) -> K + { + self.enumerate() + .max_by(|x, y| Ord::cmp(&key(&x.1), &key(&y.1))) + .map(|x| x.0) + } + + /// Return the position of the maximum element in the iterator, as + /// determined by the specified comparison function. + /// + /// If several elements are equally maximum, the position of the + /// last of them is returned. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().position_max_by(|x, y| x.cmp(y)), None); + /// + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(a.iter().position_max_by(|x, y| x.cmp(y)), Some(3)); + /// + /// let a = [1_i32, 1, -1, -1]; + /// assert_eq!(a.iter().position_max_by(|x, y| x.cmp(y)), Some(1)); + /// ``` + fn position_max_by(self, mut compare: F) -> Option + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering + { + self.enumerate() + .max_by(|x, y| compare(&x.1, &y.1)) + .map(|x| x.0) + } + + /// Return the position of the minimum element in the iterator. + /// + /// If several elements are equally minimum, the position of the + /// first of them is returned. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().position_min(), None); + /// + /// let a = [-3, 0, 1, 5, -10]; + /// assert_eq!(a.iter().position_min(), Some(4)); + /// + /// let a = [1, 1, -1, -1]; + /// assert_eq!(a.iter().position_min(), Some(2)); + /// ``` + fn position_min(self) -> Option + where Self: Sized, Self::Item: Ord + { + self.enumerate() + .min_by(|x, y| Ord::cmp(&x.1, &y.1)) + .map(|x| x.0) + } + + /// Return the position of the minimum element in the iterator, as + /// determined by the specified function. + /// + /// If several elements are equally minimum, the position of the + /// first of them is returned. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().position_min_by_key(|x| x.abs()), None); + /// + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(a.iter().position_min_by_key(|x| x.abs()), Some(1)); + /// + /// let a = [1_i32, 1, -1, -1]; + /// assert_eq!(a.iter().position_min_by_key(|x| x.abs()), Some(0)); + /// ``` + fn position_min_by_key(self, mut key: F) -> Option + where Self: Sized, K: Ord, F: FnMut(&Self::Item) -> K + { + self.enumerate() + .min_by(|x, y| Ord::cmp(&key(&x.1), &key(&y.1))) + .map(|x| x.0) + } + + /// Return the position of the minimum element in the iterator, as + /// determined by the specified comparison function. + /// + /// If several elements are equally minimum, the position of the + /// first of them is returned. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().position_min_by(|x, y| x.cmp(y)), None); + /// + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(a.iter().position_min_by(|x, y| x.cmp(y)), Some(4)); + /// + /// let a = [1_i32, 1, -1, -1]; + /// assert_eq!(a.iter().position_min_by(|x, y| x.cmp(y)), Some(2)); + /// ``` + fn position_min_by(self, mut compare: F) -> Option + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering + { + self.enumerate() + .min_by(|x, y| compare(&x.1, &y.1)) + .map(|x| x.0) + } + + /// Return the positions of the minimum and maximum elements in + /// the iterator. + /// + /// The return type [`MinMaxResult`] is an enum of three variants: + /// + /// - `NoElements` if the iterator is empty. + /// - `OneElement(xpos)` if the iterator has exactly one element. + /// - `MinMax(xpos, ypos)` is returned otherwise, where the + /// element at `xpos` ≤ the element at `ypos`. While the + /// referenced elements themselves may be equal, `xpos` cannot + /// be equal to `ypos`. + /// + /// On an iterator of length `n`, `position_minmax` does `1.5 * n` + /// comparisons, and so is faster than calling `positon_min` and + /// `position_max` separately which does `2 * n` comparisons. + /// + /// For the minimum, if several elements are equally minimum, the + /// position of the first of them is returned. For the maximum, if + /// several elements are equally maximum, the position of the last + /// of them is returned. + /// + /// The elements can be floats but no particular result is + /// guaranteed if an element is NaN. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().position_minmax(), NoElements); + /// + /// let a = [10]; + /// assert_eq!(a.iter().position_minmax(), OneElement(0)); + /// + /// let a = [-3, 0, 1, 5, -10]; + /// assert_eq!(a.iter().position_minmax(), MinMax(4, 3)); + /// + /// let a = [1, 1, -1, -1]; + /// assert_eq!(a.iter().position_minmax(), MinMax(2, 1)); + /// ``` + /// + /// [`MinMaxResult`]: enum.MinMaxResult.html + fn position_minmax(self) -> MinMaxResult + where Self: Sized, Self::Item: PartialOrd + { + use crate::MinMaxResult::{NoElements, OneElement, MinMax}; + match minmax::minmax_impl(self.enumerate(), |_| (), |x, y, _, _| x.1 < y.1) { + NoElements => NoElements, + OneElement(x) => OneElement(x.0), + MinMax(x, y) => MinMax(x.0, y.0), + } + } + + /// Return the postions of the minimum and maximum elements of an + /// iterator, as determined by the specified function. + /// + /// The return value is a variant of [`MinMaxResult`] like for + /// [`position_minmax`]. + /// + /// For the minimum, if several elements are equally minimum, the + /// position of the first of them is returned. For the maximum, if + /// several elements are equally maximum, the position of the last + /// of them is returned. + /// + /// The keys can be floats but no particular result is guaranteed + /// if a key is NaN. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().position_minmax_by_key(|x| x.abs()), NoElements); + /// + /// let a = [10_i32]; + /// assert_eq!(a.iter().position_minmax_by_key(|x| x.abs()), OneElement(0)); + /// + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(a.iter().position_minmax_by_key(|x| x.abs()), MinMax(1, 4)); + /// + /// let a = [1_i32, 1, -1, -1]; + /// assert_eq!(a.iter().position_minmax_by_key(|x| x.abs()), MinMax(0, 3)); + /// ``` + /// + /// [`MinMaxResult`]: enum.MinMaxResult.html + /// [`position_minmax`]: #method.position_minmax + fn position_minmax_by_key(self, mut key: F) -> MinMaxResult + where Self: Sized, K: PartialOrd, F: FnMut(&Self::Item) -> K + { + use crate::MinMaxResult::{NoElements, OneElement, MinMax}; + match self.enumerate().minmax_by_key(|e| key(&e.1)) { + NoElements => NoElements, + OneElement(x) => OneElement(x.0), + MinMax(x, y) => MinMax(x.0, y.0), + } + } + + /// Return the postions of the minimum and maximum elements of an + /// iterator, as determined by the specified comparison function. + /// + /// The return value is a variant of [`MinMaxResult`] like for + /// [`position_minmax`]. + /// + /// For the minimum, if several elements are equally minimum, the + /// position of the first of them is returned. For the maximum, if + /// several elements are equally maximum, the position of the last + /// of them is returned. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; + /// + /// let a: [i32; 0] = []; + /// assert_eq!(a.iter().position_minmax_by(|x, y| x.cmp(y)), NoElements); + /// + /// let a = [10_i32]; + /// assert_eq!(a.iter().position_minmax_by(|x, y| x.cmp(y)), OneElement(0)); + /// + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(a.iter().position_minmax_by(|x, y| x.cmp(y)), MinMax(4, 3)); + /// + /// let a = [1_i32, 1, -1, -1]; + /// assert_eq!(a.iter().position_minmax_by(|x, y| x.cmp(y)), MinMax(2, 1)); + /// ``` + /// + /// [`MinMaxResult`]: enum.MinMaxResult.html + /// [`position_minmax`]: #method.position_minmax + fn position_minmax_by(self, mut compare: F) -> MinMaxResult + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering + { + use crate::MinMaxResult::{NoElements, OneElement, MinMax}; + match self.enumerate().minmax_by(|x, y| compare(&x.1, &y.1)) { + NoElements => NoElements, + OneElement(x) => OneElement(x.0), + MinMax(x, y) => MinMax(x.0, y.0), + } + } + + /// If the iterator yields exactly one element, that element will be returned, otherwise + /// an error will be returned containing an iterator that has the same output as the input + /// iterator. + /// + /// This provides an additional layer of validation over just calling `Iterator::next()`. + /// If your assumption that there should only be one element yielded is false this provides + /// the opportunity to detect and handle that, preventing errors at a distance. + /// + /// # Examples + /// ``` + /// use itertools::Itertools; + /// + /// assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2); + /// assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4)); + /// assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5)); + /// assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0)); + /// ``` + fn exactly_one(mut self) -> Result> + where + Self: Sized, + { + match self.next() { + Some(first) => { + match self.next() { + Some(second) => { + Err(ExactlyOneError::new((Some(first), Some(second)), self)) + } + None => { + Ok(first) + } + } + } + None => Err(ExactlyOneError::new((None, None), self)), + } + } +} + +impl Itertools for T where T: Iterator { } + +/// Return `true` if both iterables produce equal sequences +/// (elements pairwise equal and sequences of the same length), +/// `false` otherwise. +/// +/// This is an `IntoIterator` enabled function that is similar to the standard +/// library method `Iterator::eq`. +/// +/// ``` +/// assert!(itertools::equal(vec![1, 2, 3], 1..4)); +/// assert!(!itertools::equal(&[0, 0], &[0, 0, 0])); +/// ``` +pub fn equal(a: I, b: J) -> bool + where I: IntoIterator, + J: IntoIterator, + I::Item: PartialEq +{ + let mut ia = a.into_iter(); + let mut ib = b.into_iter(); + loop { + match ia.next() { + Some(x) => match ib.next() { + Some(y) => if x != y { return false; }, + None => return false, + }, + None => return ib.next().is_none() + } + } +} + +/// Assert that two iterables produce equal sequences, with the same +/// semantics as *equal(a, b)*. +/// +/// **Panics** on assertion failure with a message that shows the +/// two iteration elements. +/// +/// ```ignore +/// assert_equal("exceed".split('c'), "excess".split('c')); +/// // ^PANIC: panicked at 'Failed assertion Some("eed") == Some("ess") for iteration 1', +/// ``` +pub fn assert_equal(a: I, b: J) + where I: IntoIterator, + J: IntoIterator, + I::Item: fmt::Debug + PartialEq, + J::Item: fmt::Debug, +{ + let mut ia = a.into_iter(); + let mut ib = b.into_iter(); + let mut i = 0; + loop { + match (ia.next(), ib.next()) { + (None, None) => return, + (a, b) => { + let equal = match (&a, &b) { + (&Some(ref a), &Some(ref b)) => a == b, + _ => false, + }; + assert!(equal, "Failed assertion {a:?} == {b:?} for iteration {i}", + i=i, a=a, b=b); + i += 1; + } + } + } +} + +/// Partition a sequence using predicate `pred` so that elements +/// that map to `true` are placed before elements which map to `false`. +/// +/// The order within the partitions is arbitrary. +/// +/// Return the index of the split point. +/// +/// ``` +/// use itertools::partition; +/// +/// # // use repeated numbers to not promise any ordering +/// let mut data = [7, 1, 1, 7, 1, 1, 7]; +/// let split_index = partition(&mut data, |elt| *elt >= 3); +/// +/// assert_eq!(data, [7, 7, 7, 1, 1, 1, 1]); +/// assert_eq!(split_index, 3); +/// ``` +pub fn partition<'a, A: 'a, I, F>(iter: I, mut pred: F) -> usize + where I: IntoIterator, + I::IntoIter: DoubleEndedIterator, + F: FnMut(&A) -> bool +{ + let mut split_index = 0; + let mut iter = iter.into_iter(); + 'main: while let Some(front) = iter.next() { + if !pred(front) { + loop { + match iter.next_back() { + Some(back) => if pred(back) { + std::mem::swap(front, back); + break; + }, + None => break 'main, + } + } + } + split_index += 1; + } + split_index +} + +/// An enum used for controlling the execution of `.fold_while()`. +/// +/// See [`.fold_while()`](trait.Itertools.html#method.fold_while) for more information. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum FoldWhile { + /// Continue folding with this value + Continue(T), + /// Fold is complete and will return this value + Done(T), +} + +impl FoldWhile { + /// Return the value in the continue or done. + pub fn into_inner(self) -> T { + match self { + FoldWhile::Continue(x) | FoldWhile::Done(x) => x, + } + } + + /// Return true if `self` is `Done`, false if it is `Continue`. + pub fn is_done(&self) -> bool { + match *self { + FoldWhile::Continue(_) => false, + FoldWhile::Done(_) => true, + } + } +} diff --git a/src/rust/vendor/itertools/src/merge_join.rs b/src/rust/vendor/itertools/src/merge_join.rs new file mode 100644 index 000000000..0f87ae42e --- /dev/null +++ b/src/rust/vendor/itertools/src/merge_join.rs @@ -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(left: I, right: J, cmp_fn: F) + -> MergeJoinBy + 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 { + left: PutBack>, + right: PutBack>, + cmp_fn: F +} + +impl Clone for MergeJoinBy + where I: Iterator, + J: Iterator, + PutBack>: Clone, + PutBack>: Clone, + F: Clone, +{ + clone_fields!(left, right, cmp_fn); +} + +impl fmt::Debug for MergeJoinBy + where I: Iterator + fmt::Debug, + I::Item: fmt::Debug, + J: Iterator + fmt::Debug, + J::Item: fmt::Debug, +{ + debug_fmt_fields!(MergeJoinBy, left, right); +} + +impl Iterator for MergeJoinBy + where I: Iterator, + J: Iterator, + F: FnMut(&I::Item, &J::Item) -> Ordering +{ + type Item = EitherOrBoth; + + fn next(&mut self) -> Option { + 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) { + 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 { + 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 { + 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), + }, + } + } + } +} diff --git a/src/rust/vendor/itertools/src/minmax.rs b/src/rust/vendor/itertools/src/minmax.rs new file mode 100644 index 000000000..38180ef6d --- /dev/null +++ b/src/rust/vendor/itertools/src/minmax.rs @@ -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 { + /// 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 MinMaxResult { + /// `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 = 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(mut it: I, mut key_for: F, + mut lt: L) -> MinMaxResult + 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) +} diff --git a/src/rust/vendor/itertools/src/multipeek_impl.rs b/src/rust/vendor/itertools/src/multipeek_impl.rs new file mode 100644 index 000000000..0b64e1d7a --- /dev/null +++ b/src/rust/vendor/itertools/src/multipeek_impl.rs @@ -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 + where I: Iterator +{ + iter: Fuse, + buf: VecDeque, + index: usize, +} + +/// An iterator adaptor that allows the user to peek at multiple `.next()` +/// values without advancing the base iterator. +pub fn multipeek(iterable: I) -> MultiPeek + where I: IntoIterator +{ + MultiPeek { + iter: iterable.into_iter().fuse(), + buf: VecDeque::new(), + index: 0, + } +} + +impl MultiPeek + where I: Iterator +{ + /// Reset the peeking “cursor” + pub fn reset_peek(&mut self) { + self.index = 0; + } +} + +impl MultiPeek { + /// 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 PeekingNext for MultiPeek + where I: Iterator, +{ + fn peeking_next(&mut self, accept: F) -> Option + 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 Iterator for MultiPeek + where I: Iterator +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + self.index = 0; + if self.buf.is_empty() { + self.iter.next() + } else { + self.buf.pop_front() + } + } + + fn size_hint(&self) -> (usize, Option) { + size_hint::add_scalar(self.iter.size_hint(), self.buf.len()) + } +} + +// Same size +impl ExactSizeIterator for MultiPeek + where I: ExactSizeIterator +{} + + diff --git a/src/rust/vendor/itertools/src/pad_tail.rs b/src/rust/vendor/itertools/src/pad_tail.rs new file mode 100644 index 000000000..8d9d5ffa5 --- /dev/null +++ b/src/rust/vendor/itertools/src/pad_tail.rs @@ -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 { + iter: Fuse, + min: usize, + pos: usize, + filler: F, +} + +/// Create a new **PadUsing** iterator. +pub fn pad_using(iter: I, min: usize, filler: F) -> PadUsing + where I: Iterator, + F: FnMut(usize) -> I::Item +{ + PadUsing { + iter: iter.fuse(), + min, + pos: 0, + filler, + } +} + +impl Iterator for PadUsing + where I: Iterator, + F: FnMut(usize) -> I::Item +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.iter.next() { + None => { + if self.pos < self.min { + let e = Some((self.filler)(self.pos)); + self.pos += 1; + e + } else { + None + } + }, + e => { + self.pos += 1; + e + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let tail = self.min.saturating_sub(self.pos); + size_hint::max(self.iter.size_hint(), (tail, Some(tail))) + } +} + +impl DoubleEndedIterator for PadUsing + where I: DoubleEndedIterator + ExactSizeIterator, + F: FnMut(usize) -> I::Item +{ + fn next_back(&mut self) -> Option { + if self.min == 0 { + self.iter.next_back() + } else if self.iter.len() >= self.min { + self.min -= 1; + self.iter.next_back() + } else { + self.min -= 1; + Some((self.filler)(self.min)) + } + } +} + +impl ExactSizeIterator for PadUsing + where I: ExactSizeIterator, + F: FnMut(usize) -> I::Item +{} diff --git a/src/rust/vendor/itertools/src/peeking_take_while.rs b/src/rust/vendor/itertools/src/peeking_take_while.rs new file mode 100644 index 000000000..b404904d1 --- /dev/null +++ b/src/rust/vendor/itertools/src/peeking_take_while.rs @@ -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(&mut self, accept: F) -> Option + where F: FnOnce(&Self::Item) -> bool; +} + +impl PeekingNext for Peekable + where I: Iterator, +{ + fn peeking_next(&mut self, accept: F) -> Option + where F: FnOnce(&Self::Item) -> bool + { + if let Some(r) = self.peek() { + if !accept(r) { + return None; + } + } + self.next() + } +} + +impl PeekingNext for PutBack + where I: Iterator, +{ + fn peeking_next(&mut self, accept: F) -> Option + 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 PeekingNext for PutBackN + where I: Iterator, +{ + fn peeking_next(&mut self, accept: F) -> Option + 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(iter: &mut I, f: F) -> PeekingTakeWhile + 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.iter.peeking_next(&mut self.f) + } + + fn size_hint(&self) -> (usize, Option) { + 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(&mut self, accept: F) -> Option + 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 } +#[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 } diff --git a/src/rust/vendor/itertools/src/permutations.rs b/src/rust/vendor/itertools/src/permutations.rs new file mode 100644 index 000000000..fb4dd5085 --- /dev/null +++ b/src/rust/vendor/itertools/src/permutations.rs @@ -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 { + vals: LazyBuffer, + state: PermutationState, +} + +impl Clone for Permutations + 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, + cycles: Vec, + } +} + +enum CompleteStateRemaining { + Known(usize), + Overflow, +} + +impl fmt::Debug for Permutations + where I: Iterator + fmt::Debug, + I::Item: fmt::Debug, +{ + debug_fmt_fields!(Permutations, vals, state); +} + +pub fn permutations(iter: I, k: usize) -> Permutations { + 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 Iterator for Permutations +where + I: Iterator, + I::Item: Clone +{ + type Item = Vec; + + fn next(&mut self) -> Option { + 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) { + 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 Permutations +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 = (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) + } + } + } +} diff --git a/src/rust/vendor/itertools/src/process_results_impl.rs b/src/rust/vendor/itertools/src/process_results_impl.rs new file mode 100644 index 000000000..c819f5029 --- /dev/null +++ b/src/rust/vendor/itertools/src/process_results_impl.rs @@ -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> +{ + type Item = T; + + fn next(&mut self) -> Option { + 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) { + 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` 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; +/// +/// let first_values: Vec = vec![Ok(1), Ok(0), Ok(3)]; +/// let second_values: Vec = 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(iterable: I, processor: F) -> Result + where I: IntoIterator>, + F: FnOnce(ProcessResults) -> R +{ + let iter = iterable.into_iter(); + let mut error = Ok(()); + + let result = processor(ProcessResults { error: &mut error, iter }); + + error.map(|_| result) +} diff --git a/src/rust/vendor/itertools/src/put_back_n_impl.rs b/src/rust/vendor/itertools/src/put_back_n_impl.rs new file mode 100644 index 000000000..dcb28946e --- /dev/null +++ b/src/rust/vendor/itertools/src/put_back_n_impl.rs @@ -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 { + top: Vec, + 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(iterable: I) -> PutBackN + where I: IntoIterator +{ + PutBackN { + top: Vec::new(), + iter: iterable.into_iter(), + } +} + +impl PutBackN { + /// 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 Iterator for PutBackN { + type Item = I::Item; + #[inline] + fn next(&mut self) -> Option { + if self.top.is_empty() { + self.iter.next() + } else { + self.top.pop() + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + size_hint::add_scalar(self.iter.size_hint(), self.top.len()) + } +} + diff --git a/src/rust/vendor/itertools/src/rciter_impl.rs b/src/rust/vendor/itertools/src/rciter_impl.rs new file mode 100644 index 000000000..6ee90ad31 --- /dev/null +++ b/src/rust/vendor/itertools/src/rciter_impl.rs @@ -0,0 +1,96 @@ + +use std::iter::IntoIterator; +use std::rc::Rc; +use std::cell::RefCell; + +/// A wrapper for `Rc>`, that implements the `Iterator` trait. +#[derive(Debug)] +pub struct RcIter { + /// The boxed iterator. + pub rciter: Rc>, +} + +/// Return an iterator inside a `Rc>` 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(iterable: I) -> RcIter + where I: IntoIterator +{ + RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) } +} + +impl Clone for RcIter { + #[inline] + clone_fields!(rciter); +} + +impl Iterator for RcIter + where I: Iterator +{ + type Item = A; + #[inline] + fn next(&mut self) -> Option { + self.rciter.borrow_mut().next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // 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 DoubleEndedIterator for RcIter + where I: DoubleEndedIterator +{ + #[inline] + fn next_back(&mut self) -> Option { + self.rciter.borrow_mut().next_back() + } +} + +/// Return an iterator from `&RcIter` (by simply cloning it). +impl<'a, I> IntoIterator for &'a RcIter + where I: Iterator +{ + type Item = I::Item; + type IntoIter = RcIter; + + fn into_iter(self) -> RcIter { + self.clone() + } +} diff --git a/src/rust/vendor/itertools/src/repeatn.rs b/src/rust/vendor/itertools/src/repeatn.rs new file mode 100644 index 000000000..8bc485083 --- /dev/null +++ b/src/rust/vendor/itertools/src/repeatn.rs @@ -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 { + elt: Option, + n: usize, +} + +/// Create an iterator that produces `n` repetitions of `element`. +pub fn repeat_n(element: A, n: usize) -> RepeatN + where A: Clone, +{ + if n == 0 { + RepeatN { elt: None, n, } + } else { + RepeatN { elt: Some(element), n, } + } +} + +impl Iterator for RepeatN + where A: Clone +{ + type Item = A; + + fn next(&mut self) -> Option { + 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) { + (self.n, Some(self.n)) + } +} + +impl DoubleEndedIterator for RepeatN + where A: Clone +{ + #[inline] + fn next_back(&mut self) -> Option { + self.next() + } +} + +impl ExactSizeIterator for RepeatN + where A: Clone +{} diff --git a/src/rust/vendor/itertools/src/size_hint.rs b/src/rust/vendor/itertools/src/size_hint.rs new file mode 100644 index 000000000..be54443f2 --- /dev/null +++ b/src/rust/vendor/itertools/src/size_hint.rs @@ -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); + +/// 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) +} diff --git a/src/rust/vendor/itertools/src/sources.rs b/src/rust/vendor/itertools/src/sources.rs new file mode 100644 index 000000000..17d9ff92c --- /dev/null +++ b/src/rust/vendor/itertools/src/sources.rs @@ -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, +} + +impl fmt::Debug for RepeatCall +{ + 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(function: F) -> RepeatCall + where F: FnMut() -> A +{ + RepeatCall { f: function } +} + +impl Iterator for RepeatCall + where F: FnMut() -> A +{ + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + Some((self.f)()) + } + + fn size_hint(&self) -> (usize, Option) { + (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(initial_state: St, f: F) -> Unfold + where F: FnMut(&mut St) -> Option +{ + Unfold { + f, + state: initial_state, + } +} + +impl fmt::Debug for Unfold + 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 { + f: F, + /// Internal state that will be passed to the closure on the next iteration + pub state: St, +} + +impl Iterator for Unfold + where F: FnMut(&mut St) -> Option +{ + type Item = A; + + #[inline] + fn next(&mut self) -> Option { + (self.f)(&mut self.state) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // 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 { + state: St, + f: F, +} + +impl fmt::Debug for Iterate + where St: fmt::Debug, +{ + debug_fmt_fields!(Iterate, state); +} + +impl Iterator for Iterate + where F: FnMut(&St) -> St +{ + type Item = St; + + #[inline] + fn next(&mut self) -> Option { + let next_state = (self.f)(&self.state); + Some(mem::replace(&mut self.state, next_state)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (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(initial_value: St, f: F) -> Iterate + where F: FnMut(&St) -> St +{ + Iterate { + state: initial_value, + f, + } +} diff --git a/src/rust/vendor/itertools/src/tee.rs b/src/rust/vendor/itertools/src/tee.rs new file mode 100644 index 000000000..aa4be41be --- /dev/null +++ b/src/rust/vendor/itertools/src/tee.rs @@ -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 { + backlog: VecDeque, + 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 + where I: Iterator +{ + rcbuffer: Rc>>, + id: bool, +} + +pub fn new(iter: I) -> (Tee, Tee) + 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 Iterator for Tee + where I: Iterator, + I::Item: Clone +{ + type Item = I::Item; + fn next(&mut self) -> Option { + // .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) { + 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 ExactSizeIterator for Tee + where I: ExactSizeIterator, + I::Item: Clone +{} diff --git a/src/rust/vendor/itertools/src/tuple_impl.rs b/src/rust/vendor/itertools/src/tuple_impl.rs new file mode 100644 index 000000000..f205f01b3 --- /dev/null +++ b/src/rust/vendor/itertools/src/tuple_impl.rs @@ -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 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 + where T: HomogeneousTuple +{ + cur: usize, + buf: T::Buffer, +} + +impl TupleBuffer + where T: HomogeneousTuple +{ + fn new(buf: T::Buffer) -> Self { + TupleBuffer { + cur: 0, + buf, + } + } +} + +impl Iterator for TupleBuffer + where T: HomogeneousTuple +{ + type Item = T::Item; + + fn next(&mut self) -> Option { + 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) { + 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 ExactSizeIterator for TupleBuffer + 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 + where I: Iterator, + T: HomogeneousTuple +{ + iter: Fuse, + buf: T::Buffer, +} + +/// Create a new tuples iterator. +pub fn tuples(iter: I) -> Tuples + where I: Iterator, + T: HomogeneousTuple +{ + Tuples { + iter: iter.fuse(), + buf: Default::default(), + } +} + +impl Iterator for Tuples + where I: Iterator, + T: HomogeneousTuple +{ + type Item = T; + + fn next(&mut self) -> Option { + T::collect_from_iter(&mut self.iter, &mut self.buf) + } +} + +impl Tuples + where I: Iterator, + 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 { + 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 + where I: Iterator, + T: HomogeneousTuple +{ + iter: I, + last: Option, +} + +/// Create a new tuple windows iterator. +pub fn tuple_windows(mut iter: I) -> TupleWindows + where I: Iterator, + 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 Iterator for TupleWindows + where I: Iterator, + T: HomogeneousTuple + Clone, + T::Item: Clone +{ + type Item = T; + + fn next(&mut self) -> Option { + 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]> + AsMut<[Option]>; + + fn collect_from_iter(iter: I, buf: &mut Self::Buffer) -> Option + where I: IntoIterator; + + fn collect_from_iter_no_buf(iter: I) -> Option + where I: IntoIterator; + + 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(iter: I, buf: &mut Self::Buffer) -> Option + where I: IntoIterator + { + 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(iter: I) -> Option + where I: IntoIterator + { + 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); diff --git a/src/rust/vendor/itertools/src/unique_impl.rs b/src/rust/vendor/itertools/src/unique_impl.rs new file mode 100644 index 000000000..cf8675c18 --- /dev/null +++ b/src/rust/vendor/itertools/src/unique_impl.rs @@ -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 { + iter: I, + // Use a hashmap for the entry API + used: HashMap, + f: F, +} + +impl fmt::Debug for UniqueBy + 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(iter: I, f: F) -> UniqueBy + 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(mut used: HashMap, iterable: I) -> usize + where I: IntoIterator, + K: Hash + Eq, +{ + let iter = iterable.into_iter(); + let current_used = used.len(); + used.extend(iter.map(|key| (key, ()))); + used.len() - current_used +} + +impl Iterator for UniqueBy + where I: Iterator, + V: Eq + Hash, + F: FnMut(&I::Item) -> V +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + 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) { + 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 Iterator for Unique + where I: Iterator, + I::Item: Eq + Hash + Clone +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + 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) { + 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 { + iter: UniqueBy, +} + +impl fmt::Debug for Unique + where I: Iterator + fmt::Debug, + I::Item: Hash + Eq + fmt::Debug, +{ + debug_fmt_fields!(Unique, iter); +} + +pub fn unique(iter: I) -> Unique + where I: Iterator, + I::Item: Eq + Hash, +{ + Unique { + iter: UniqueBy { + iter, + used: HashMap::new(), + f: (), + } + } +} diff --git a/src/rust/vendor/itertools/src/with_position.rs b/src/rust/vendor/itertools/src/with_position.rs new file mode 100644 index 000000000..1440fb6f5 --- /dev/null +++ b/src/rust/vendor/itertools/src/with_position.rs @@ -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`. +/// +/// 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 + where I: Iterator, +{ + handled_first: bool, + peekable: Peekable>, +} + +impl Clone for WithPosition + where I: Clone + Iterator, + I::Item: Clone, +{ + clone_fields!(handled_first, peekable); +} + +/// Create a new `WithPosition` iterator. +pub fn with_position(iter: I) -> WithPosition + 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 { + /// 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 Position { + /// 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 Iterator for WithPosition { + type Item = Position; + + fn next(&mut self) -> Option { + match self.peekable.next() { + Some(item) => { + if !self.handled_first { + // Haven't seen the first item yet, and there is one to give. + self.handled_first = true; + // Peek to see if this is also the last item, + // in which case tag it as `Only`. + match self.peekable.peek() { + Some(_) => Some(Position::First(item)), + None => Some(Position::Only(item)), + } + } else { + // Have seen the first item, and there's something left. + // Peek to see if this is the last item. + match self.peekable.peek() { + Some(_) => Some(Position::Middle(item)), + None => Some(Position::Last(item)), + } + } + } + // Iterator is finished. + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.peekable.size_hint() + } +} + +impl ExactSizeIterator for WithPosition + where I: ExactSizeIterator, +{ } diff --git a/src/rust/vendor/itertools/src/zip_eq_impl.rs b/src/rust/vendor/itertools/src/zip_eq_impl.rs new file mode 100644 index 000000000..857465da4 --- /dev/null +++ b/src/rust/vendor/itertools/src/zip_eq_impl.rs @@ -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 { + 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: I, j: J) -> ZipEq + where I: IntoIterator, + J: IntoIterator +{ + ZipEq { + a: i.into_iter(), + b: j.into_iter(), + } +} + +impl Iterator for ZipEq + where I: Iterator, + J: Iterator +{ + type Item = (I::Item, J::Item); + + fn next(&mut self) -> Option { + 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) { + size_hint::min(self.a.size_hint(), self.b.size_hint()) + } +} + +impl ExactSizeIterator for ZipEq + where I: ExactSizeIterator, + J: ExactSizeIterator +{} diff --git a/src/rust/vendor/itertools/src/zip_longest.rs b/src/rust/vendor/itertools/src/zip_longest.rs new file mode 100644 index 000000000..1395c8428 --- /dev/null +++ b/src/rust/vendor/itertools/src/zip_longest.rs @@ -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 { + a: Fuse, + b: Fuse, +} + +/// Create a new `ZipLongest` iterator. +pub fn zip_longest(a: T, b: U) -> ZipLongest + where T: Iterator, + U: Iterator +{ + ZipLongest { + a: a.fuse(), + b: b.fuse(), + } +} + +impl Iterator for ZipLongest + where T: Iterator, + U: Iterator +{ + type Item = EitherOrBoth; + + #[inline] + fn next(&mut self) -> Option { + 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) { + size_hint::max(self.a.size_hint(), self.b.size_hint()) + } +} + +impl DoubleEndedIterator for ZipLongest + where T: DoubleEndedIterator + ExactSizeIterator, + U: DoubleEndedIterator + ExactSizeIterator +{ + #[inline] + fn next_back(&mut self) -> Option { + 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 ExactSizeIterator for ZipLongest + where T: ExactSizeIterator, + U: ExactSizeIterator +{} diff --git a/src/rust/vendor/itertools/src/ziptuple.rs b/src/rust/vendor/itertools/src/ziptuple.rs new file mode 100644 index 000000000..2dc3ea5e0 --- /dev/null +++ b/src/rust/vendor/itertools/src/ziptuple.rs @@ -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, +} + +/// 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) -> Zip + where Zip: From, + Zip: 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 + { + 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) + { + 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); diff --git a/src/rust/vendor/itertools/tests/adaptors_no_collect.rs b/src/rust/vendor/itertools/tests/adaptors_no_collect.rs new file mode 100644 index 000000000..a47f906f9 --- /dev/null +++ b/src/rust/vendor/itertools/tests/adaptors_no_collect.rs @@ -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.curr += 1; + + if self.curr == self.max { + panic!( + "Input iterator reached maximum of {} suggesting collection by adaptor", + self.max + ); + } + + Some(()) + } +} + +fn no_collect_test(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)) +} \ No newline at end of file diff --git a/src/rust/vendor/itertools/tests/fold_specialization.rs b/src/rust/vendor/itertools/tests/fold_specialization.rs new file mode 100644 index 000000000..a984b40b8 --- /dev/null +++ b/src/rust/vendor/itertools/tests/fold_specialization.rs @@ -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())); +} diff --git a/src/rust/vendor/itertools/tests/merge_join.rs b/src/rust/vendor/itertools/tests/merge_join.rs new file mode 100644 index 000000000..3280b7d4e --- /dev/null +++ b/src/rust/vendor/itertools/tests/merge_join.rs @@ -0,0 +1,108 @@ +use itertools::EitherOrBoth; +use itertools::free::merge_join_by; + +#[test] +fn empty() { + let left: Vec = vec![]; + let right: Vec = vec![]; + let expected_result: Vec> = vec![]; + let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) + .collect::>(); + assert_eq!(expected_result, actual_result); +} + +#[test] +fn left_only() { + let left: Vec = vec![1,2,3]; + let right: Vec = vec![]; + let expected_result: Vec> = vec![ + EitherOrBoth::Left(1), + EitherOrBoth::Left(2), + EitherOrBoth::Left(3) + ]; + let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) + .collect::>(); + assert_eq!(expected_result, actual_result); +} + +#[test] +fn right_only() { + let left: Vec = vec![]; + let right: Vec = vec![1,2,3]; + let expected_result: Vec> = vec![ + EitherOrBoth::Right(1), + EitherOrBoth::Right(2), + EitherOrBoth::Right(3) + ]; + let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) + .collect::>(); + assert_eq!(expected_result, actual_result); +} + +#[test] +fn first_left_then_right() { + let left: Vec = vec![1,2,3]; + let right: Vec = vec![4,5,6]; + let expected_result: Vec> = vec![ + EitherOrBoth::Left(1), + EitherOrBoth::Left(2), + EitherOrBoth::Left(3), + EitherOrBoth::Right(4), + EitherOrBoth::Right(5), + EitherOrBoth::Right(6) + ]; + let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) + .collect::>(); + assert_eq!(expected_result, actual_result); +} + +#[test] +fn first_right_then_left() { + let left: Vec = vec![4,5,6]; + let right: Vec = vec![1,2,3]; + let expected_result: Vec> = vec![ + EitherOrBoth::Right(1), + EitherOrBoth::Right(2), + EitherOrBoth::Right(3), + EitherOrBoth::Left(4), + EitherOrBoth::Left(5), + EitherOrBoth::Left(6) + ]; + let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) + .collect::>(); + assert_eq!(expected_result, actual_result); +} + +#[test] +fn interspersed_left_and_right() { + let left: Vec = vec![1,3,5]; + let right: Vec = vec![2,4,6]; + let expected_result: Vec> = vec![ + EitherOrBoth::Left(1), + EitherOrBoth::Right(2), + EitherOrBoth::Left(3), + EitherOrBoth::Right(4), + EitherOrBoth::Left(5), + EitherOrBoth::Right(6) + ]; + let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) + .collect::>(); + assert_eq!(expected_result, actual_result); +} + +#[test] +fn overlapping_left_and_right() { + let left: Vec = vec![1,3,4,6]; + let right: Vec = vec![2,3,4,5]; + let expected_result: Vec> = vec![ + EitherOrBoth::Left(1), + EitherOrBoth::Right(2), + EitherOrBoth::Both(3, 3), + EitherOrBoth::Both(4, 4), + EitherOrBoth::Right(5), + EitherOrBoth::Left(6) + ]; + let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) + .collect::>(); + assert_eq!(expected_result, actual_result); +} diff --git a/src/rust/vendor/itertools/tests/peeking_take_while.rs b/src/rust/vendor/itertools/tests/peeking_take_while.rs new file mode 100644 index 000000000..a1147027e --- /dev/null +++ b/src/rust/vendor/itertools/tests/peeking_take_while.rs @@ -0,0 +1,50 @@ +use itertools::Itertools; +use itertools::{put_back, put_back_n}; + +#[test] +fn peeking_take_while_peekable() { + let mut r = (0..10).peekable(); + r.peeking_take_while(|x| *x <= 3).count(); + assert_eq!(r.next(), Some(4)); +} + +#[test] +fn peeking_take_while_put_back() { + let mut r = put_back(0..10); + r.peeking_take_while(|x| *x <= 3).count(); + assert_eq!(r.next(), Some(4)); + r.peeking_take_while(|_| true).count(); + assert_eq!(r.next(), None); +} + +#[test] +fn peeking_take_while_put_back_n() { + let mut r = put_back_n(6..10); + for elt in (0..6).rev() { + r.put_back(elt); + } + r.peeking_take_while(|x| *x <= 3).count(); + assert_eq!(r.next(), Some(4)); + r.peeking_take_while(|_| true).count(); + assert_eq!(r.next(), None); +} + +#[test] +fn peeking_take_while_slice_iter() { + let v = [1, 2, 3, 4, 5, 6]; + let mut r = v.iter(); + r.peeking_take_while(|x| **x <= 3).count(); + assert_eq!(r.next(), Some(&4)); + r.peeking_take_while(|_| true).count(); + assert_eq!(r.next(), None); +} + +#[test] +fn peeking_take_while_slice_iter_rev() { + let v = [1, 2, 3, 4, 5, 6]; + let mut r = v.iter().rev(); + r.peeking_take_while(|x| **x >= 3).count(); + assert_eq!(r.next(), Some(&2)); + r.peeking_take_while(|_| true).count(); + assert_eq!(r.next(), None); +} diff --git a/src/rust/vendor/itertools/tests/quick.rs b/src/rust/vendor/itertools/tests/quick.rs new file mode 100644 index 000000000..683ba7ae4 --- /dev/null +++ b/src/rust/vendor/itertools/tests/quick.rs @@ -0,0 +1,1157 @@ +//! The purpose of these tests is to cover corner cases of iterators +//! and adaptors. +//! +//! In particular we test the tedious size_hint and exact size correctness. + +use quickcheck as qc; +use std::default::Default; +use std::ops::Range; +use std::cmp::{max, min, Ordering}; +use std::collections::HashSet; +use itertools::Itertools; +use itertools::{ + multizip, + EitherOrBoth, + iproduct, + izip, +}; +use itertools::free::{ + cloned, + enumerate, + multipeek, + put_back, + put_back_n, + rciter, + zip, + zip_eq, +}; + +use rand::Rng; +use rand::seq::SliceRandom; +use quickcheck::TestResult; + +/// Trait for size hint modifier types +trait HintKind: Copy + Send + qc::Arbitrary { + fn loosen_bounds(&self, org_hint: (usize, Option)) -> (usize, Option); +} + +/// Exact size hint variant that leaves hints unchanged +#[derive(Clone, Copy, Debug)] +struct Exact {} + +impl HintKind for Exact { + fn loosen_bounds(&self, org_hint: (usize, Option)) -> (usize, Option) { + org_hint + } +} + +impl qc::Arbitrary for Exact { + fn arbitrary(_: &mut G) -> Self { + Exact {} + } +} + +/// Inexact size hint variant to simulate imprecise (but valid) size hints +/// +/// Will always decrease the lower bound and increase the upper bound +/// of the size hint by set amounts. +#[derive(Clone, Copy, Debug)] +struct Inexact { + underestimate: usize, + overestimate: usize, +} + +impl HintKind for Inexact { + fn loosen_bounds(&self, org_hint: (usize, Option)) -> (usize, Option) { + let (org_lower, org_upper) = org_hint; + (org_lower.saturating_sub(self.underestimate), + org_upper.and_then(move |x| x.checked_add(self.overestimate))) + } +} + +impl qc::Arbitrary for Inexact { + fn arbitrary(g: &mut G) -> Self { + let ue_value = usize::arbitrary(g); + let oe_value = usize::arbitrary(g); + // Compensate for quickcheck using extreme values too rarely + let ue_choices = &[0, ue_value, usize::max_value()]; + let oe_choices = &[0, oe_value, usize::max_value()]; + Inexact { + underestimate: *ue_choices.choose(g).unwrap(), + overestimate: *oe_choices.choose(g).unwrap(), + } + } + + fn shrink(&self) -> Box> { + let underestimate_value = self.underestimate; + let overestimate_value = self.overestimate; + Box::new( + underestimate_value.shrink().flat_map(move |ue_value| + overestimate_value.shrink().map(move |oe_value| + Inexact { + underestimate: ue_value, + overestimate: oe_value, + } + ) + ) + ) + } +} + +/// Our base iterator that we can impl Arbitrary for +/// +/// By default we'll return inexact bounds estimates for size_hint +/// to make tests harder to pass. +/// +/// NOTE: Iter is tricky and is not fused, to help catch bugs. +/// At the end it will return None once, then return Some(0), +/// then return None again. +#[derive(Clone, Debug)] +struct Iter { + iterator: Range, + // fuse/done flag + fuse_flag: i32, + hint_kind: SK, +} + +impl Iter where HK: HintKind +{ + fn new(it: Range, hint_kind: HK) -> Self { + Iter { + iterator: it, + fuse_flag: 0, + hint_kind, + } + } +} + +impl Iterator for Iter + where Range: Iterator, + as Iterator>::Item: Default, + HK: HintKind, +{ + type Item = as Iterator>::Item; + + fn next(&mut self) -> Option + { + let elt = self.iterator.next(); + if elt.is_none() { + self.fuse_flag += 1; + // check fuse flag + if self.fuse_flag == 2 { + return Some(Default::default()) + } + } + elt + } + + fn size_hint(&self) -> (usize, Option) + { + let org_hint = self.iterator.size_hint(); + self.hint_kind.loosen_bounds(org_hint) + } +} + +impl DoubleEndedIterator for Iter + where Range: DoubleEndedIterator, + as Iterator>::Item: Default, + HK: HintKind +{ + fn next_back(&mut self) -> Option { self.iterator.next_back() } +} + +impl ExactSizeIterator for Iter where Range: ExactSizeIterator, + as Iterator>::Item: Default, +{ } + +impl qc::Arbitrary for Iter + where T: qc::Arbitrary, + HK: HintKind, +{ + fn arbitrary(g: &mut G) -> Self + { + Iter::new(T::arbitrary(g)..T::arbitrary(g), HK::arbitrary(g)) + } + + fn shrink(&self) -> Box>> + { + let r = self.iterator.clone(); + let hint_kind = self.hint_kind; + Box::new( + r.start.shrink().flat_map(move |a| + r.end.shrink().map(move |b| + Iter::new(a.clone()..b, hint_kind) + ) + ) + ) + } +} + +/// A meta-iterator which yields `Iter`s whose start/endpoints are +/// increased or decreased linearly on each iteration. +#[derive(Clone, Debug)] +struct ShiftRange { + range_start: i32, + range_end: i32, + start_step: i32, + end_step: i32, + iter_count: u32, + hint_kind: HK, +} + +impl Iterator for ShiftRange where HK: HintKind { + type Item = Iter; + + fn next(&mut self) -> Option { + if self.iter_count == 0 { + return None; + } + + let iter = Iter::new(self.range_start..self.range_end, self.hint_kind); + + self.range_start += self.start_step; + self.range_end += self.end_step; + self.iter_count -= 1; + + Some(iter) + } +} + +impl ExactSizeIterator for ShiftRange { } + +impl qc::Arbitrary for ShiftRange + where HK: HintKind +{ + fn arbitrary(g: &mut G) -> Self { + const MAX_STARTING_RANGE_DIFF: i32 = 32; + const MAX_STEP_MODULO: i32 = 8; + const MAX_ITER_COUNT: u32 = 3; + + let range_start = qc::Arbitrary::arbitrary(g); + let range_end = range_start + g.gen_range(0, MAX_STARTING_RANGE_DIFF + 1); + let start_step = g.gen_range(-MAX_STEP_MODULO, MAX_STEP_MODULO + 1); + let end_step = g.gen_range(-MAX_STEP_MODULO, MAX_STEP_MODULO + 1); + let iter_count = g.gen_range(0, MAX_ITER_COUNT + 1); + let hint_kind = qc::Arbitrary::arbitrary(g); + + ShiftRange { + range_start, + range_end, + start_step, + end_step, + iter_count, + hint_kind, + } + } +} + +fn correct_count(get_it: F) -> bool +where + I: Iterator, + F: Fn() -> I +{ + let mut counts = vec![get_it().count()]; + + 'outer: loop { + let mut it = get_it(); + + for _ in 0..(counts.len() - 1) { + if let None = it.next() { + panic!("Iterator shouldn't be finished, may not be deterministic"); + } + } + + if let None = it.next() { + break 'outer; + } + + counts.push(it.count()); + } + + let total_actual_count = counts.len() - 1; + + for (i, returned_count) in counts.into_iter().enumerate() { + let actual_count = total_actual_count - i; + if actual_count != returned_count { + println!("Total iterations: {} True count: {} returned count: {}", i, actual_count, returned_count); + + return false; + } + } + + true +} + +fn correct_size_hint(mut it: I) -> bool { + // record size hint at each iteration + let initial_hint = it.size_hint(); + let mut hints = Vec::with_capacity(initial_hint.0 + 1); + hints.push(initial_hint); + while let Some(_) = it.next() { + hints.push(it.size_hint()) + } + + let mut true_count = hints.len(); // start off +1 too much + + // check all the size hints + for &(low, hi) in &hints { + true_count -= 1; + if low > true_count || + (hi.is_some() && hi.unwrap() < true_count) + { + println!("True size: {:?}, size hint: {:?}", true_count, (low, hi)); + //println!("All hints: {:?}", hints); + return false + } + } + true +} + +fn exact_size(mut it: I) -> bool { + // check every iteration + let (mut low, mut hi) = it.size_hint(); + if Some(low) != hi { return false; } + while let Some(_) = it.next() { + let (xlow, xhi) = it.size_hint(); + if low != xlow + 1 { return false; } + low = xlow; + hi = xhi; + if Some(low) != hi { return false; } + } + let (low, hi) = it.size_hint(); + low == 0 && hi == Some(0) +} + +// Exact size for this case, without ExactSizeIterator +fn exact_size_for_this(mut it: I) -> bool { + // check every iteration + let (mut low, mut hi) = it.size_hint(); + if Some(low) != hi { return false; } + while let Some(_) = it.next() { + let (xlow, xhi) = it.size_hint(); + if low != xlow + 1 { return false; } + low = xlow; + hi = xhi; + if Some(low) != hi { return false; } + } + let (low, hi) = it.size_hint(); + low == 0 && hi == Some(0) +} + +/* + * NOTE: Range is broken! + * (all signed ranges are) +#[quickcheck] +fn size_range_i8(a: Iter) -> bool { + exact_size(a) +} + +#[quickcheck] +fn size_range_i16(a: Iter) -> bool { + exact_size(a) +} + +#[quickcheck] +fn size_range_u8(a: Iter) -> bool { + exact_size(a) +} + */ + +macro_rules! quickcheck { + // accept several property function definitions + // The property functions can use pattern matching and `mut` as usual + // in the function arguments, but the functions can not be generic. + {$($(#$attr:tt)* fn $fn_name:ident($($arg:tt)*) -> $ret:ty { $($code:tt)* })*} => ( + $( + #[test] + $(#$attr)* + fn $fn_name() { + fn prop($($arg)*) -> $ret { + $($code)* + } + ::quickcheck::quickcheck(quickcheck!(@fn prop [] $($arg)*)); + } + )* + ); + // parse argument list (with patterns allowed) into prop as fn(_, _) -> _ + (@fn $f:ident [$($t:tt)*]) => { + $f as fn($($t),*) -> _ + }; + (@fn $f:ident [$($p:tt)*] : $($tail:tt)*) => { + quickcheck!(@fn $f [$($p)* _] $($tail)*) + }; + (@fn $f:ident [$($p:tt)*] $t:tt $($tail:tt)*) => { + quickcheck!(@fn $f [$($p)*] $($tail)*) + }; +} + +quickcheck! { + + fn size_product(a: Iter, b: Iter) -> bool { + correct_size_hint(a.cartesian_product(b)) + } + fn size_product3(a: Iter, b: Iter, c: Iter) -> bool { + correct_size_hint(iproduct!(a, b, c)) + } + + fn correct_cartesian_product3(a: Iter, b: Iter, c: Iter, + take_manual: usize) -> () + { + // test correctness of iproduct through regular iteration (take) + // and through fold. + let ac = a.clone(); + let br = &b.clone(); + let cr = &c.clone(); + let answer: Vec<_> = ac.flat_map(move |ea| br.clone().flat_map(move |eb| cr.clone().map(move |ec| (ea, eb, ec)))).collect(); + let mut product_iter = iproduct!(a, b, c); + let mut actual = Vec::new(); + + actual.extend((&mut product_iter).take(take_manual)); + if actual.len() == take_manual { + product_iter.fold((), |(), elt| actual.push(elt)); + } + assert_eq!(answer, actual); + } + + fn size_multi_product(a: ShiftRange) -> bool { + correct_size_hint(a.multi_cartesian_product()) + } + fn correct_multi_product3(a: ShiftRange, take_manual: usize) -> () { + // Fix no. of iterators at 3 + let a = ShiftRange { iter_count: 3, ..a }; + + // test correctness of MultiProduct through regular iteration (take) + // and through fold. + let mut iters = a.clone(); + let i0 = iters.next().unwrap(); + let i1r = &iters.next().unwrap(); + let i2r = &iters.next().unwrap(); + let answer: Vec<_> = i0.flat_map(move |ei0| i1r.clone().flat_map(move |ei1| i2r.clone().map(move |ei2| vec![ei0, ei1, ei2]))).collect(); + let mut multi_product = a.clone().multi_cartesian_product(); + let mut actual = Vec::new(); + + actual.extend((&mut multi_product).take(take_manual)); + if actual.len() == take_manual { + multi_product.fold((), |(), elt| actual.push(elt)); + } + assert_eq!(answer, actual); + + assert_eq!(answer.into_iter().last(), a.clone().multi_cartesian_product().last()); + } + + #[allow(deprecated)] + fn size_step(a: Iter, s: usize) -> bool { + let mut s = s; + if s == 0 { + s += 1; // never zero + } + let filt = a.clone().dedup(); + correct_size_hint(filt.step(s)) && + exact_size(a.step(s)) + } + + #[allow(deprecated)] + fn equal_step(a: Iter, s: usize) -> bool { + let mut s = s; + if s == 0 { + s += 1; // never zero + } + let mut i = 0; + itertools::equal(a.clone().step(s), a.filter(|_| { + let keep = i % s == 0; + i += 1; + keep + })) + } + + #[allow(deprecated)] + fn equal_step_vec(a: Vec, s: usize) -> bool { + let mut s = s; + if s == 0 { + s += 1; // never zero + } + let mut i = 0; + itertools::equal(a.iter().step(s), a.iter().filter(|_| { + let keep = i % s == 0; + i += 1; + keep + })) + } + + fn size_multipeek(a: Iter, s: u8) -> bool { + let mut it = multipeek(a); + // peek a few times + for _ in 0..s { + it.peek(); + } + exact_size(it) + } + + fn equal_merge(a: Vec, b: Vec) -> bool { + let mut sa = a.clone(); + let mut sb = b.clone(); + sa.sort(); + sb.sort(); + let mut merged = sa.clone(); + merged.extend(sb.iter().cloned()); + merged.sort(); + itertools::equal(&merged, sa.iter().merge(&sb)) + } + fn size_merge(a: Iter, b: Iter) -> bool { + correct_size_hint(a.merge(b)) + } + fn size_zip(a: Iter, b: Iter, c: Iter) -> bool { + let filt = a.clone().dedup(); + correct_size_hint(multizip((filt, b.clone(), c.clone()))) && + exact_size(multizip((a, b, c))) + } + fn size_zip_rc(a: Iter, b: Iter) -> bool { + let rc = rciter(a.clone()); + correct_size_hint(multizip((&rc, &rc, b))) + } + + fn size_zip_macro(a: Iter, b: Iter, c: Iter) -> bool { + let filt = a.clone().dedup(); + correct_size_hint(izip!(filt, b.clone(), c.clone())) && + exact_size(izip!(a, b, c)) + } + fn equal_kmerge(a: Vec, b: Vec, c: Vec) -> bool { + use itertools::free::kmerge; + let mut sa = a.clone(); + let mut sb = b.clone(); + let mut sc = c.clone(); + sa.sort(); + sb.sort(); + sc.sort(); + let mut merged = sa.clone(); + merged.extend(sb.iter().cloned()); + merged.extend(sc.iter().cloned()); + merged.sort(); + itertools::equal(merged.into_iter(), kmerge(vec![sa, sb, sc])) + } + + // Any number of input iterators + fn equal_kmerge_2(mut inputs: Vec>) -> bool { + use itertools::free::kmerge; + // sort the inputs + for input in &mut inputs { + input.sort(); + } + let mut merged = inputs.concat(); + merged.sort(); + itertools::equal(merged.into_iter(), kmerge(inputs)) + } + + // Any number of input iterators + fn equal_kmerge_by_ge(mut inputs: Vec>) -> bool { + // sort the inputs + for input in &mut inputs { + input.sort(); + input.reverse(); + } + let mut merged = inputs.concat(); + merged.sort(); + merged.reverse(); + itertools::equal(merged.into_iter(), + inputs.into_iter().kmerge_by(|x, y| x >= y)) + } + + // Any number of input iterators + fn equal_kmerge_by_lt(mut inputs: Vec>) -> bool { + // sort the inputs + for input in &mut inputs { + input.sort(); + } + let mut merged = inputs.concat(); + merged.sort(); + itertools::equal(merged.into_iter(), + inputs.into_iter().kmerge_by(|x, y| x < y)) + } + + // Any number of input iterators + fn equal_kmerge_by_le(mut inputs: Vec>) -> bool { + // sort the inputs + for input in &mut inputs { + input.sort(); + } + let mut merged = inputs.concat(); + merged.sort(); + itertools::equal(merged.into_iter(), + inputs.into_iter().kmerge_by(|x, y| x <= y)) + } + fn size_kmerge(a: Iter, b: Iter, c: Iter) -> bool { + use itertools::free::kmerge; + correct_size_hint(kmerge(vec![a, b, c])) + } + fn equal_zip_eq(a: Vec, b: Vec) -> bool { + let len = std::cmp::min(a.len(), b.len()); + let a = &a[..len]; + let b = &b[..len]; + itertools::equal(zip_eq(a, b), zip(a, b)) + } + fn size_zip_longest(a: Iter, b: Iter) -> bool { + let filt = a.clone().dedup(); + let filt2 = b.clone().dedup(); + correct_size_hint(filt.zip_longest(b.clone())) && + correct_size_hint(a.clone().zip_longest(filt2)) && + exact_size(a.zip_longest(b)) + } + fn size_2_zip_longest(a: Iter, b: Iter) -> bool { + let it = a.clone().zip_longest(b.clone()); + let jt = a.clone().zip_longest(b.clone()); + itertools::equal(a.clone(), + it.filter_map(|elt| match elt { + EitherOrBoth::Both(x, _) => Some(x), + EitherOrBoth::Left(x) => Some(x), + _ => None, + } + )) + && + itertools::equal(b.clone(), + jt.filter_map(|elt| match elt { + EitherOrBoth::Both(_, y) => Some(y), + EitherOrBoth::Right(y) => Some(y), + _ => None, + } + )) + } + fn size_interleave(a: Iter, b: Iter) -> bool { + correct_size_hint(a.interleave(b)) + } + fn exact_interleave(a: Iter, b: Iter) -> bool { + exact_size_for_this(a.interleave(b)) + } + fn size_interleave_shortest(a: Iter, b: Iter) -> bool { + correct_size_hint(a.interleave_shortest(b)) + } + fn exact_interleave_shortest(a: Vec<()>, b: Vec<()>) -> bool { + exact_size_for_this(a.iter().interleave_shortest(&b)) + } + fn size_intersperse(a: Iter, x: i16) -> bool { + correct_size_hint(a.intersperse(x)) + } + fn equal_intersperse(a: Vec, x: i32) -> bool { + let mut inter = false; + let mut i = 0; + for elt in a.iter().cloned().intersperse(x) { + if inter { + if elt != x { return false } + } else { + if elt != a[i] { return false } + i += 1; + } + inter = !inter; + } + true + } + + fn equal_combinations_2(a: Vec) -> bool { + let mut v = Vec::new(); + for (i, x) in enumerate(&a) { + for y in &a[i + 1..] { + v.push((x, y)); + } + } + itertools::equal(a.iter().tuple_combinations::<(_, _)>(), v) + } + + fn collect_tuple_matches_size(a: Iter) -> bool { + let size = a.clone().count(); + a.collect_tuple::<(_, _, _)>().is_some() == (size == 3) + } + + fn correct_permutations(vals: HashSet, k: usize) -> () { + // Test permutations only on iterators of distinct integers, to prevent + // false positives. + + const MAX_N: usize = 5; + + let n = min(vals.len(), MAX_N); + let vals: HashSet = vals.into_iter().take(n).collect(); + + let perms = vals.iter().permutations(k); + + let mut actual = HashSet::new(); + + for perm in perms { + assert_eq!(perm.len(), k); + + let all_items_valid = perm.iter().all(|p| vals.contains(p)); + assert!(all_items_valid, "perm contains value not from input: {:?}", perm); + + // Check that all perm items are distinct + let distinct_len = { + let perm_set: HashSet<_> = perm.iter().collect(); + perm_set.len() + }; + assert_eq!(perm.len(), distinct_len); + + // Check that the perm is new + assert!(actual.insert(perm.clone()), "perm already encountered: {:?}", perm); + } + } + + fn permutations_lexic_order(a: usize, b: usize) -> () { + let a = a % 6; + let b = b % 6; + + let n = max(a, b); + let k = min (a, b); + + let expected_first: Vec = (0..k).collect(); + let expected_last: Vec = ((n - k)..n).rev().collect(); + + let mut perms = (0..n).permutations(k); + + let mut curr_perm = match perms.next() { + Some(p) => p, + None => { return; } + }; + + assert_eq!(expected_first, curr_perm); + + while let Some(next_perm) = perms.next() { + assert!( + next_perm > curr_perm, + "next perm isn't greater-than current; next_perm={:?} curr_perm={:?} n={}", + next_perm, curr_perm, n + ); + + curr_perm = next_perm; + } + + assert_eq!(expected_last, curr_perm); + + } + + fn permutations_count(n: usize, k: usize) -> bool { + let n = n % 6; + + correct_count(|| (0..n).permutations(k)) + } + + fn permutations_size(a: Iter, k: usize) -> bool { + correct_size_hint(a.take(5).permutations(k)) + } + + fn permutations_k0_yields_once(n: usize) -> () { + let k = 0; + let expected: Vec> = vec![vec![]]; + let actual = (0..n).permutations(k).collect_vec(); + + assert_eq!(expected, actual); + } +} + +quickcheck! { + fn equal_dedup(a: Vec) -> bool { + let mut b = a.clone(); + b.dedup(); + itertools::equal(&b, a.iter().dedup()) + } +} + +quickcheck! { + fn equal_dedup_by(a: Vec<(i32, i32)>) -> bool { + let mut b = a.clone(); + b.dedup_by(|x, y| x.0==y.0); + itertools::equal(&b, a.iter().dedup_by(|x, y| x.0==y.0)) + } +} + +quickcheck! { + fn size_dedup(a: Vec) -> bool { + correct_size_hint(a.iter().dedup()) + } +} + +quickcheck! { + fn size_dedup_by(a: Vec<(i32, i32)>) -> bool { + correct_size_hint(a.iter().dedup_by(|x, y| x.0==y.0)) + } +} + +quickcheck! { + fn exact_repeatn((n, x): (usize, i32)) -> bool { + let it = itertools::repeat_n(x, n); + exact_size(it) + } +} + +quickcheck! { + fn size_put_back(a: Vec, x: Option) -> bool { + let mut it = put_back(a.into_iter()); + match x { + Some(t) => it.put_back(t), + None => {} + } + correct_size_hint(it) + } +} + +quickcheck! { + fn size_put_backn(a: Vec, b: Vec) -> bool { + let mut it = put_back_n(a.into_iter()); + for elt in b { + it.put_back(elt) + } + correct_size_hint(it) + } +} + +quickcheck! { + fn size_tee(a: Vec) -> bool { + let (mut t1, mut t2) = a.iter().tee(); + t1.next(); + t1.next(); + t2.next(); + exact_size(t1) && exact_size(t2) + } +} + +quickcheck! { + fn size_tee_2(a: Vec) -> bool { + let (mut t1, mut t2) = a.iter().dedup().tee(); + t1.next(); + t1.next(); + t2.next(); + correct_size_hint(t1) && correct_size_hint(t2) + } +} + +quickcheck! { + fn size_take_while_ref(a: Vec, stop: u8) -> bool { + correct_size_hint(a.iter().take_while_ref(|x| **x != stop)) + } +} + +quickcheck! { + fn equal_partition(a: Vec) -> bool { + let mut a = a; + let mut ap = a.clone(); + let split_index = itertools::partition(&mut ap, |x| *x >= 0); + let parted = (0..split_index).all(|i| ap[i] >= 0) && + (split_index..a.len()).all(|i| ap[i] < 0); + + a.sort(); + ap.sort(); + parted && (a == ap) + } +} + +quickcheck! { + fn size_combinations(it: Iter) -> bool { + correct_size_hint(it.tuple_combinations::<(_, _)>()) + } +} + +quickcheck! { + fn equal_combinations(it: Iter) -> bool { + let values = it.clone().collect_vec(); + let mut cmb = it.tuple_combinations(); + for i in 0..values.len() { + for j in i+1..values.len() { + let pair = (values[i], values[j]); + if pair != cmb.next().unwrap() { + return false; + } + } + } + cmb.next() == None + } +} + +quickcheck! { + fn size_pad_tail(it: Iter, pad: u8) -> bool { + correct_size_hint(it.clone().pad_using(pad as usize, |_| 0)) && + correct_size_hint(it.dropping(1).rev().pad_using(pad as usize, |_| 0)) + } +} + +quickcheck! { + fn size_pad_tail2(it: Iter, pad: u8) -> bool { + exact_size(it.pad_using(pad as usize, |_| 0)) + } +} + +quickcheck! { + fn size_unique(it: Iter) -> bool { + correct_size_hint(it.unique()) + } + + fn count_unique(it: Vec, take_first: u8) -> () { + let answer = { + let mut v = it.clone(); + v.sort(); v.dedup(); + v.len() + }; + let mut iter = cloned(&it).unique(); + let first_count = (&mut iter).take(take_first as usize).count(); + let rest_count = iter.count(); + assert_eq!(answer, first_count + rest_count); + } +} + +quickcheck! { + fn fuzz_group_by_lazy_1(it: Iter) -> bool { + let jt = it.clone(); + let groups = it.group_by(|k| *k); + let res = itertools::equal(jt, groups.into_iter().flat_map(|(_, x)| x)); + res + } +} + +quickcheck! { + fn fuzz_group_by_lazy_2(data: Vec) -> bool { + let groups = data.iter().group_by(|k| *k / 10); + let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x)); + res + } +} + +quickcheck! { + fn fuzz_group_by_lazy_3(data: Vec) -> bool { + let grouper = data.iter().group_by(|k| *k / 10); + let groups = grouper.into_iter().collect_vec(); + let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x)); + res + } +} + +quickcheck! { + fn fuzz_group_by_lazy_duo(data: Vec, order: Vec<(bool, bool)>) -> bool { + let grouper = data.iter().group_by(|k| *k / 3); + let mut groups1 = grouper.into_iter(); + let mut groups2 = grouper.into_iter(); + let mut elts = Vec::<&u8>::new(); + let mut old_groups = Vec::new(); + + let tup1 = |(_, b)| b; + for &(ord, consume_now) in &order { + let iter = &mut [&mut groups1, &mut groups2][ord as usize]; + match iter.next() { + Some((_, gr)) => if consume_now { + for og in old_groups.drain(..) { + elts.extend(og); + } + elts.extend(gr); + } else { + old_groups.push(gr); + }, + None => break, + } + } + for og in old_groups.drain(..) { + elts.extend(og); + } + for gr in groups1.map(&tup1) { elts.extend(gr); } + for gr in groups2.map(&tup1) { elts.extend(gr); } + itertools::assert_equal(&data, elts); + true + } +} + +quickcheck! { + fn equal_chunks_lazy(a: Vec, size: u8) -> bool { + let mut size = size; + if size == 0 { + size += 1; + } + let chunks = a.iter().chunks(size as usize); + let it = a.chunks(size as usize); + for (a, b) in chunks.into_iter().zip(it) { + if !itertools::equal(a, b) { + return false; + } + } + true + } +} + +quickcheck! { + fn equal_tuple_windows_1(a: Vec) -> bool { + let x = a.windows(1).map(|s| (&s[0], )); + let y = a.iter().tuple_windows::<(_,)>(); + itertools::equal(x, y) + } + + fn equal_tuple_windows_2(a: Vec) -> bool { + let x = a.windows(2).map(|s| (&s[0], &s[1])); + let y = a.iter().tuple_windows::<(_, _)>(); + itertools::equal(x, y) + } + + fn equal_tuple_windows_3(a: Vec) -> bool { + let x = a.windows(3).map(|s| (&s[0], &s[1], &s[2])); + let y = a.iter().tuple_windows::<(_, _, _)>(); + itertools::equal(x, y) + } + + fn equal_tuple_windows_4(a: Vec) -> bool { + let x = a.windows(4).map(|s| (&s[0], &s[1], &s[2], &s[3])); + let y = a.iter().tuple_windows::<(_, _, _, _)>(); + itertools::equal(x, y) + } + + fn equal_tuples_1(a: Vec) -> bool { + let x = a.chunks(1).map(|s| (&s[0], )); + let y = a.iter().tuples::<(_,)>(); + itertools::equal(x, y) + } + + fn equal_tuples_2(a: Vec) -> bool { + let x = a.chunks(2).filter(|s| s.len() == 2).map(|s| (&s[0], &s[1])); + let y = a.iter().tuples::<(_, _)>(); + itertools::equal(x, y) + } + + fn equal_tuples_3(a: Vec) -> bool { + let x = a.chunks(3).filter(|s| s.len() == 3).map(|s| (&s[0], &s[1], &s[2])); + let y = a.iter().tuples::<(_, _, _)>(); + itertools::equal(x, y) + } + + fn equal_tuples_4(a: Vec) -> bool { + let x = a.chunks(4).filter(|s| s.len() == 4).map(|s| (&s[0], &s[1], &s[2], &s[3])); + let y = a.iter().tuples::<(_, _, _, _)>(); + itertools::equal(x, y) + } + + fn exact_tuple_buffer(a: Vec) -> bool { + let mut iter = a.iter().tuples::<(_, _, _, _)>(); + (&mut iter).last(); + let buffer = iter.into_buffer(); + assert_eq!(buffer.len(), a.len() % 4); + exact_size(buffer) + } +} + +// with_position +quickcheck! { + fn with_position_exact_size_1(a: Vec) -> bool { + exact_size_for_this(a.iter().with_position()) + } + fn with_position_exact_size_2(a: Iter) -> bool { + exact_size_for_this(a.with_position()) + } +} + +quickcheck! { + fn correct_group_map_modulo_key(a: Vec, modulo: u8) -> () { + let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0` + let count = a.len(); + let lookup = a.into_iter().map(|i| (i % modulo, i)).into_group_map(); + + assert_eq!(lookup.values().flat_map(|vals| vals.iter()).count(), count); + + for (&key, vals) in lookup.iter() { + assert!(vals.iter().all(|&val| val % modulo == key)); + } + } +} + +/// A peculiar type: Equality compares both tuple items, but ordering only the +/// first item. This is so we can check the stability property easily. +#[derive(Clone, Debug, PartialEq, Eq)] +struct Val(u32, u32); + +impl PartialOrd for Val { + fn partial_cmp(&self, other: &Val) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl Ord for Val { + fn cmp(&self, other: &Val) -> Ordering { + self.0.cmp(&other.0) + } +} + +impl qc::Arbitrary for Val { + fn arbitrary(g: &mut G) -> Self { + let (x, y) = <(u32, u32)>::arbitrary(g); + Val(x, y) + } + fn shrink(&self) -> Box> { + Box::new((self.0, self.1).shrink().map(|(x, y)| Val(x, y))) + } +} + +quickcheck! { + fn minmax(a: Vec) -> bool { + use itertools::MinMaxResult; + + + let minmax = a.iter().minmax(); + let expected = match a.len() { + 0 => MinMaxResult::NoElements, + 1 => MinMaxResult::OneElement(&a[0]), + _ => MinMaxResult::MinMax(a.iter().min().unwrap(), + a.iter().max().unwrap()), + }; + minmax == expected + } +} + +quickcheck! { + fn minmax_f64(a: Vec) -> TestResult { + use itertools::MinMaxResult; + + if a.iter().any(|x| x.is_nan()) { + return TestResult::discard(); + } + + let min = cloned(&a).fold1(f64::min); + let max = cloned(&a).fold1(f64::max); + + let minmax = cloned(&a).minmax(); + let expected = match a.len() { + 0 => MinMaxResult::NoElements, + 1 => MinMaxResult::OneElement(min.unwrap()), + _ => MinMaxResult::MinMax(min.unwrap(), max.unwrap()), + }; + TestResult::from_bool(minmax == expected) + } +} + +quickcheck! { + #[allow(deprecated)] + fn tree_fold1_f64(mut a: Vec) -> TestResult { + fn collapse_adjacent(x: Vec, mut f: F) -> Vec + where F: FnMut(f64, f64) -> f64 + { + let mut out = Vec::new(); + for i in (0..x.len()).step(2) { + if i == x.len()-1 { + out.push(x[i]) + } else { + out.push(f(x[i], x[i+1])); + } + } + out + } + + if a.iter().any(|x| x.is_nan()) { + return TestResult::discard(); + } + + let actual = a.iter().cloned().tree_fold1(f64::atan2); + + while a.len() > 1 { + a = collapse_adjacent(a, f64::atan2); + } + let expected = a.pop(); + + TestResult::from_bool(actual == expected) + } +} + +quickcheck! { + fn exactly_one_i32(a: Vec) -> TestResult { + let ret = a.iter().cloned().exactly_one(); + match a.len() { + 1 => TestResult::from_bool(ret.unwrap() == a[0]), + _ => TestResult::from_bool(ret.unwrap_err().eq(a.iter().cloned())), + } + } +} diff --git a/src/rust/vendor/itertools/tests/specializations.rs b/src/rust/vendor/itertools/tests/specializations.rs new file mode 100644 index 000000000..ef51bbedf --- /dev/null +++ b/src/rust/vendor/itertools/tests/specializations.rs @@ -0,0 +1,149 @@ +use itertools::{EitherOrBoth, Itertools}; +use std::fmt::Debug; +use std::ops::BitXor; +use quickcheck::quickcheck; + +struct Unspecialized(I); +impl Iterator for Unspecialized +where + I: Iterator, +{ + type Item = I::Item; + + #[inline(always)] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +fn check_specialized<'a, V, IterItem, Iter, F>(iterator: &Iter, mapper: F) +where + V: Eq + Debug, + IterItem: 'a, + Iter: Iterator + Clone + 'a, + F: Fn(Box + 'a>) -> V, +{ + assert_eq!( + mapper(Box::new(Unspecialized(iterator.clone()))), + mapper(Box::new(iterator.clone())) + ) +} + +fn check_specialized_count_last_nth_sizeh<'a, IterItem, Iter>( + it: &Iter, + known_expected_size: Option, +) where + IterItem: 'a + Eq + Debug, + Iter: Iterator + Clone + 'a, +{ + let size = it.clone().count(); + if let Some(expected_size) = known_expected_size { + assert_eq!(size, expected_size); + } + check_specialized(it, |i| i.count()); + check_specialized(it, |i| i.last()); + for n in 0..size + 2 { + check_specialized(it, |mut i| i.nth(n)); + } + let mut it_sh = it.clone(); + for n in 0..size + 2 { + let len = it_sh.clone().count(); + let (min, max) = it_sh.size_hint(); + assert_eq!((size - n.min(size)), len); + assert!(min <= len); + if let Some(max) = max { + assert!(len <= max); + } + it_sh.next(); + } +} + +fn check_specialized_fold_xor<'a, IterItem, Iter>(it: &Iter) +where + IterItem: 'a + + BitXor + + Eq + + Debug + + BitXor<::Output, Output = ::Output> + + Clone, + ::Output: + BitXor::Output> + Eq + Debug + Clone, + Iter: Iterator + Clone + 'a, +{ + check_specialized(it, |mut i| { + let first = i.next().map(|f| f.clone() ^ (f.clone() ^ f)); + i.fold(first, |acc, v: IterItem| acc.map(move |a| v ^ a)) + }); +} + +fn put_back_test(test_vec: Vec, known_expected_size: Option) { + { + // Lexical lifetimes support + let pb = itertools::put_back(test_vec.iter()); + check_specialized_count_last_nth_sizeh(&pb, known_expected_size); + check_specialized_fold_xor(&pb); + } + + let mut pb = itertools::put_back(test_vec.into_iter()); + pb.put_back(1); + check_specialized_count_last_nth_sizeh(&pb, known_expected_size.map(|x| x + 1)); + check_specialized_fold_xor(&pb) +} + +#[test] +fn put_back() { + put_back_test(vec![7, 4, 1], Some(3)); +} + +quickcheck! { + fn put_back_qc(test_vec: Vec) -> () { + put_back_test(test_vec, None) + } +} + +fn merge_join_by_test(i1: Vec, i2: Vec, known_expected_size: Option) { + let i1 = i1.into_iter(); + let i2 = i2.into_iter(); + let mjb = i1.clone().merge_join_by(i2.clone(), std::cmp::Ord::cmp); + check_specialized_count_last_nth_sizeh(&mjb, known_expected_size); + // Rust 1.24 compatibility: + fn eob_left_z(eob: EitherOrBoth) -> usize { + eob.left().unwrap_or(0) + } + fn eob_right_z(eob: EitherOrBoth) -> usize { + eob.left().unwrap_or(0) + } + fn eob_both_z(eob: EitherOrBoth) -> usize { + let (a, b) = eob.both().unwrap_or((0, 0)); + assert_eq!(a, b); + a + } + check_specialized_fold_xor(&mjb.clone().map(eob_left_z)); + check_specialized_fold_xor(&mjb.clone().map(eob_right_z)); + check_specialized_fold_xor(&mjb.clone().map(eob_both_z)); + + // And the other way around + let mjb = i2.merge_join_by(i1, std::cmp::Ord::cmp); + check_specialized_count_last_nth_sizeh(&mjb, known_expected_size); + check_specialized_fold_xor(&mjb.clone().map(eob_left_z)); + check_specialized_fold_xor(&mjb.clone().map(eob_right_z)); + check_specialized_fold_xor(&mjb.clone().map(eob_both_z)); +} + +#[test] +fn merge_join_by() { + let i1 = vec![1, 3, 5, 7, 8, 9]; + let i2 = vec![0, 3, 4, 5]; + merge_join_by_test(i1, i2, Some(8)); +} + +quickcheck! { + fn merge_join_by_qc(i1: Vec, i2: Vec) -> () { + merge_join_by_test(i1, i2, None) + } +} diff --git a/src/rust/vendor/itertools/tests/test_core.rs b/src/rust/vendor/itertools/tests/test_core.rs new file mode 100644 index 000000000..5861653da --- /dev/null +++ b/src/rust/vendor/itertools/tests/test_core.rs @@ -0,0 +1,272 @@ +//! 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. +#![no_std] + +use core::iter; +use itertools as it; +use crate::it::Itertools; +use crate::it::interleave; +use crate::it::multizip; +use crate::it::free::put_back; +use crate::it::iproduct; +use crate::it::izip; + +#[test] +fn product2() { + let s = "αβ"; + + let mut prod = iproduct!(s.chars(), 0..2); + assert!(prod.next() == Some(('α', 0))); + assert!(prod.next() == Some(('α', 1))); + assert!(prod.next() == Some(('β', 0))); + assert!(prod.next() == Some(('β', 1))); + assert!(prod.next() == None); +} + +#[test] +fn product_temporary() { + for (_x, _y, _z) in iproduct!( + [0, 1, 2].iter().cloned(), + [0, 1, 2].iter().cloned(), + [0, 1, 2].iter().cloned()) + { + // ok + } +} + + +#[test] +fn izip_macro() { + let mut zip = izip!(2..3); + assert!(zip.next() == Some(2)); + assert!(zip.next().is_none()); + + let mut zip = izip!(0..3, 0..2, 0..2i8); + for i in 0..2 { + assert!((i as usize, i, i as i8) == zip.next().unwrap()); + } + assert!(zip.next().is_none()); + + let xs: [isize; 0] = []; + let mut zip = izip!(0..3, 0..2, 0..2i8, &xs); + assert!(zip.next().is_none()); +} + +#[test] +fn izip2() { + let _zip1: iter::Zip<_, _> = izip!(1.., 2..); + let _zip2: iter::Zip<_, _> = izip!(1.., 2.., ); +} + +#[test] +fn izip3() { + let mut zip: iter::Map, _> = izip!(0..3, 0..2, 0..2i8); + for i in 0..2 { + assert!((i as usize, i, i as i8) == zip.next().unwrap()); + } + assert!(zip.next().is_none()); +} + +#[test] +fn multizip3() { + let mut zip = multizip((0..3, 0..2, 0..2i8)); + for i in 0..2 { + assert!((i as usize, i, i as i8) == zip.next().unwrap()); + } + assert!(zip.next().is_none()); + + let xs: [isize; 0] = []; + let mut zip = multizip((0..3, 0..2, 0..2i8, xs.iter())); + assert!(zip.next().is_none()); + + for (_, _, _, _, _) in multizip((0..3, 0..2, xs.iter(), &xs, xs.to_vec())) { + /* test compiles */ + } +} + +#[test] +fn write_to() { + let xs = [7, 9, 8]; + let mut ys = [0; 5]; + let cnt = ys.iter_mut().set_from(xs.iter().map(|x| *x)); + assert!(cnt == xs.len()); + assert!(ys == [7, 9, 8, 0, 0]); + + let cnt = ys.iter_mut().set_from(0..10); + assert!(cnt == ys.len()); + assert!(ys == [0, 1, 2, 3, 4]); +} + +#[test] +fn test_interleave() { + let xs: [u8; 0] = []; + let ys = [7u8, 9, 8, 10]; + let zs = [2u8, 77]; + let it = interleave(xs.iter(), ys.iter()); + it::assert_equal(it, ys.iter()); + + let rs = [7u8, 2, 9, 77, 8, 10]; + let it = interleave(ys.iter(), zs.iter()); + it::assert_equal(it, rs.iter()); +} + +#[allow(deprecated)] +#[test] +fn foreach() { + let xs = [1i32, 2, 3]; + let mut sum = 0; + xs.iter().foreach(|elt| sum += *elt); + assert!(sum == 6); +} + +#[test] +fn dropping() { + let xs = [1, 2, 3]; + let mut it = xs.iter().dropping(2); + assert_eq!(it.next(), Some(&3)); + assert!(it.next().is_none()); + let mut it = xs.iter().dropping(5); + assert!(it.next().is_none()); +} + +#[test] +fn batching() { + let xs = [0, 1, 2, 1, 3]; + let ys = [(0, 1), (2, 1)]; + + // An iterator that gathers elements up in pairs + let pit = xs.iter().cloned().batching(|it| { + match it.next() { + None => None, + Some(x) => match it.next() { + None => None, + Some(y) => Some((x, y)), + } + } + }); + it::assert_equal(pit, ys.iter().cloned()); +} + +#[test] +fn test_put_back() { + let xs = [0, 1, 1, 1, 2, 1, 3, 3]; + let mut pb = put_back(xs.iter().cloned()); + pb.next(); + pb.put_back(1); + pb.put_back(0); + it::assert_equal(pb, xs.iter().cloned()); +} + +#[allow(deprecated)] +#[test] +fn step() { + it::assert_equal((0..10).step(1), 0..10); + it::assert_equal((0..10).step(2), (0..10).filter(|x: &i32| *x % 2 == 0)); + it::assert_equal((0..10).step(10), 0..1); +} + +#[allow(deprecated)] +#[test] +fn merge() { + it::assert_equal((0..10).step(2).merge((1..10).step(2)), 0..10); +} + + +#[test] +fn repeatn() { + let s = "α"; + let mut it = it::repeat_n(s, 3); + assert_eq!(it.len(), 3); + assert_eq!(it.next(), Some(s)); + assert_eq!(it.next(), Some(s)); + assert_eq!(it.next(), Some(s)); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); +} + +#[test] +fn count_clones() { + // Check that RepeatN only clones N - 1 times. + + use core::cell::Cell; + #[derive(PartialEq, Debug)] + struct Foo { + n: Cell + } + + impl Clone for Foo + { + fn clone(&self) -> Self + { + let n = self.n.get(); + self.n.set(n + 1); + Foo { n: Cell::new(n + 1) } + } + } + + + for n in 0..10 { + let f = Foo{n: Cell::new(0)}; + let it = it::repeat_n(f, n); + // drain it + let last = it.last(); + if n == 0 { + assert_eq!(last, None); + } else { + assert_eq!(last, Some(Foo{n: Cell::new(n - 1)})); + } + } +} + +#[test] +fn part() { + let mut data = [7, 1, 1, 9, 1, 1, 3]; + let i = it::partition(&mut data, |elt| *elt >= 3); + assert_eq!(i, 3); + assert_eq!(data, [7, 3, 9, 1, 1, 1, 1]); + + let i = it::partition(&mut data, |elt| *elt == 1); + assert_eq!(i, 4); + assert_eq!(data, [1, 1, 1, 1, 9, 3, 7]); + + let mut data = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + let i = it::partition(&mut data, |elt| *elt % 3 == 0); + assert_eq!(i, 3); + assert_eq!(data, [9, 6, 3, 4, 5, 2, 7, 8, 1]); +} + +#[test] +fn tree_fold1() { + for i in 0..100 { + assert_eq!((0..i).tree_fold1(|x, y| x + y), (0..i).fold1(|x, y| x + y)); + } +} + +#[test] +fn exactly_one() { + assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2); + assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4)); + assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5)); + assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0)); +} + +#[test] +fn sum1() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..0].iter().cloned().sum1::(), None); + assert_eq!(v[1..2].iter().cloned().sum1::(), Some(1)); + assert_eq!(v[1..3].iter().cloned().sum1::(), Some(3)); + assert_eq!(v.iter().cloned().sum1::(), Some(55)); +} + +#[test] +fn product1() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..0].iter().cloned().product1::(), None); + assert_eq!(v[..1].iter().cloned().product1::(), Some(0)); + assert_eq!(v[1..3].iter().cloned().product1::(), Some(2)); + assert_eq!(v[1..5].iter().cloned().product1::(), Some(24)); +} diff --git a/src/rust/vendor/itertools/tests/test_std.rs b/src/rust/vendor/itertools/tests/test_std.rs new file mode 100644 index 000000000..ba077848c --- /dev/null +++ b/src/rust/vendor/itertools/tests/test_std.rs @@ -0,0 +1,793 @@ +use permutohedron; +use itertools as it; +use crate::it::Itertools; +use crate::it::multizip; +use crate::it::multipeek; +use crate::it::free::rciter; +use crate::it::free::put_back_n; +use crate::it::FoldWhile; +use crate::it::cloned; +use crate::it::iproduct; +use crate::it::izip; + +#[test] +fn product3() { + let prod = iproduct!(0..3, 0..2, 0..2); + assert_eq!(prod.size_hint(), (12, Some(12))); + let v = prod.collect_vec(); + for i in 0..3 { + for j in 0..2 { + for k in 0..2 { + assert!((i, j, k) == v[(i * 2 * 2 + j * 2 + k) as usize]); + } + } + } + for (_, _, _, _) in iproduct!(0..3, 0..2, 0..2, 0..3) { + /* test compiles */ + } +} + +#[test] +fn interleave_shortest() { + let v0: Vec = vec![0, 2, 4]; + let v1: Vec = vec![1, 3, 5, 7]; + let it = v0.into_iter().interleave_shortest(v1.into_iter()); + assert_eq!(it.size_hint(), (6, Some(6))); + assert_eq!(it.collect_vec(), vec![0, 1, 2, 3, 4, 5]); + + let v0: Vec = vec![0, 2, 4, 6, 8]; + let v1: Vec = vec![1, 3, 5]; + let it = v0.into_iter().interleave_shortest(v1.into_iter()); + assert_eq!(it.size_hint(), (7, Some(7))); + assert_eq!(it.collect_vec(), vec![0, 1, 2, 3, 4, 5, 6]); + + let i0 = ::std::iter::repeat(0); + let v1: Vec<_> = vec![1, 3, 5]; + let it = i0.interleave_shortest(v1.into_iter()); + assert_eq!(it.size_hint(), (7, Some(7))); + + let v0: Vec<_> = vec![0, 2, 4]; + let i1 = ::std::iter::repeat(1); + let it = v0.into_iter().interleave_shortest(i1); + assert_eq!(it.size_hint(), (6, Some(6))); +} + + +#[test] +fn unique_by() { + let xs = ["aaa", "bbbbb", "aa", "ccc", "bbbb", "aaaaa", "cccc"]; + let ys = ["aaa", "bbbbb", "ccc"]; + it::assert_equal(ys.iter(), xs.iter().unique_by(|x| x[..2].to_string())); +} + +#[test] +fn unique() { + let xs = [0, 1, 2, 3, 2, 1, 3]; + let ys = [0, 1, 2, 3]; + it::assert_equal(ys.iter(), xs.iter().unique()); + let xs = [0, 1]; + let ys = [0, 1]; + it::assert_equal(ys.iter(), xs.iter().unique()); +} + +#[test] +fn intersperse() { + let xs = ["a", "", "b", "c"]; + let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); + let text: String = v.concat(); + assert_eq!(text, "a, , b, c".to_string()); + + let ys = [0, 1, 2, 3]; + let mut it = ys[..0].iter().map(|x| *x).intersperse(1); + assert!(it.next() == None); +} + +#[test] +fn dedup() { + let xs = [0, 1, 1, 1, 2, 1, 3, 3]; + let ys = [0, 1, 2, 1, 3]; + it::assert_equal(ys.iter(), xs.iter().dedup()); + let xs = [0, 0, 0, 0, 0]; + let ys = [0]; + it::assert_equal(ys.iter(), xs.iter().dedup()); + + let xs = [0, 1, 1, 1, 2, 1, 3, 3]; + let ys = [0, 1, 2, 1, 3]; + let mut xs_d = Vec::new(); + xs.iter().dedup().fold((), |(), &elt| xs_d.push(elt)); + assert_eq!(&xs_d, &ys); +} + +#[test] +fn dedup_by() { + let xs = [(0, 0), (0, 1), (1, 1), (2, 1), (0, 2), (3, 1), (0, 3), (1, 3)]; + let ys = [(0, 0), (0, 1), (0, 2), (3, 1), (0, 3)]; + it::assert_equal(ys.iter(), xs.iter().dedup_by(|x, y| x.1==y.1)); + let xs = [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)]; + let ys = [(0, 1)]; + it::assert_equal(ys.iter(), xs.iter().dedup_by(|x, y| x.0==y.0)); + + let xs = [(0, 0), (0, 1), (1, 1), (2, 1), (0, 2), (3, 1), (0, 3), (1, 3)]; + let ys = [(0, 0), (0, 1), (0, 2), (3, 1), (0, 3)]; + let mut xs_d = Vec::new(); + xs.iter().dedup_by(|x, y| x.1==y.1).fold((), |(), &elt| xs_d.push(elt)); + assert_eq!(&xs_d, &ys); +} + +#[test] +fn all_equal() { + assert!("".chars().all_equal()); + assert!("A".chars().all_equal()); + assert!(!"AABBCCC".chars().all_equal()); + assert!("AAAAAAA".chars().all_equal()); + for (_key, mut sub) in &"AABBCCC".chars().group_by(|&x| x) { + assert!(sub.all_equal()); + } +} + +#[test] +fn test_put_back_n() { + let xs = [0, 1, 1, 1, 2, 1, 3, 3]; + let mut pb = put_back_n(xs.iter().cloned()); + pb.next(); + pb.next(); + pb.put_back(1); + pb.put_back(0); + it::assert_equal(pb, xs.iter().cloned()); +} + +#[test] +fn tee() { + let xs = [0, 1, 2, 3]; + let (mut t1, mut t2) = xs.iter().cloned().tee(); + assert_eq!(t1.next(), Some(0)); + assert_eq!(t2.next(), Some(0)); + assert_eq!(t1.next(), Some(1)); + assert_eq!(t1.next(), Some(2)); + assert_eq!(t1.next(), Some(3)); + assert_eq!(t1.next(), None); + assert_eq!(t2.next(), Some(1)); + assert_eq!(t2.next(), Some(2)); + assert_eq!(t1.next(), None); + assert_eq!(t2.next(), Some(3)); + assert_eq!(t2.next(), None); + assert_eq!(t1.next(), None); + assert_eq!(t2.next(), None); + + let (t1, t2) = xs.iter().cloned().tee(); + it::assert_equal(t1, xs.iter().cloned()); + it::assert_equal(t2, xs.iter().cloned()); + + let (t1, t2) = xs.iter().cloned().tee(); + it::assert_equal(t1.zip(t2), xs.iter().cloned().zip(xs.iter().cloned())); +} + + +#[test] +fn test_rciter() { + let xs = [0, 1, 1, 1, 2, 1, 3, 5, 6]; + + let mut r1 = rciter(xs.iter().cloned()); + let mut r2 = r1.clone(); + assert_eq!(r1.next(), Some(0)); + assert_eq!(r2.next(), Some(1)); + let mut z = r1.zip(r2); + assert_eq!(z.next(), Some((1, 1))); + assert_eq!(z.next(), Some((2, 1))); + assert_eq!(z.next(), Some((3, 5))); + assert_eq!(z.next(), None); + + // test intoiterator + let r1 = rciter(0..5); + let mut z = izip!(&r1, r1); + assert_eq!(z.next(), Some((0, 1))); +} + +#[allow(deprecated)] +#[test] +fn trait_pointers() { + struct ByRef<'r, I: ?Sized>(&'r mut I) ; + + impl<'r, X, I: ?Sized> Iterator for ByRef<'r, I> where + I: 'r + Iterator + { + type Item = X; + fn next(&mut self) -> Option + { + self.0.next() + } + } + + let mut it = Box::new(0..10) as Box>; + assert_eq!(it.next(), Some(0)); + + { + /* make sure foreach works on non-Sized */ + let jt: &mut dyn Iterator = &mut *it; + assert_eq!(jt.next(), Some(1)); + + { + let mut r = ByRef(jt); + assert_eq!(r.next(), Some(2)); + } + + assert_eq!(jt.find_position(|x| *x == 4), Some((1, 4))); + jt.foreach(|_| ()); + } +} + +#[test] +fn merge_by() { + let odd : Vec<(u32, &str)> = vec![(1, "hello"), (3, "world"), (5, "!")]; + let even = vec![(2, "foo"), (4, "bar"), (6, "baz")]; + let expected = vec![(1, "hello"), (2, "foo"), (3, "world"), (4, "bar"), (5, "!"), (6, "baz")]; + let results = odd.iter().merge_by(even.iter(), |a, b| a.0 <= b.0); + it::assert_equal(results, expected.iter()); +} + +#[test] +fn merge_by_btree() { + use std::collections::BTreeMap; + let mut bt1 = BTreeMap::new(); + bt1.insert("hello", 1); + bt1.insert("world", 3); + let mut bt2 = BTreeMap::new(); + bt2.insert("foo", 2); + bt2.insert("bar", 4); + let results = bt1.into_iter().merge_by(bt2.into_iter(), |a, b| a.0 <= b.0 ); + let expected = vec![("bar", 4), ("foo", 2), ("hello", 1), ("world", 3)]; + it::assert_equal(results, expected.into_iter()); +} + +#[allow(deprecated)] +#[test] +fn kmerge() { + let its = (0..4).map(|s| (s..10).step(4)); + + it::assert_equal(its.kmerge(), 0..10); +} + +#[allow(deprecated)] +#[test] +fn kmerge_2() { + let its = vec![3, 2, 1, 0].into_iter().map(|s| (s..10).step(4)); + + it::assert_equal(its.kmerge(), 0..10); +} + +#[test] +fn kmerge_empty() { + let its = (0..4).map(|_| 0..0); + assert_eq!(its.kmerge().next(), None); +} + +#[test] +fn kmerge_size_hint() { + let its = (0..5).map(|_| (0..10)); + assert_eq!(its.kmerge().size_hint(), (50, Some(50))); +} + +#[test] +fn kmerge_empty_size_hint() { + let its = (0..5).map(|_| (0..0)); + assert_eq!(its.kmerge().size_hint(), (0, Some(0))); +} + +#[test] +fn join() { + let many = [1, 2, 3]; + let one = [1]; + let none: Vec = vec![]; + + assert_eq!(many.iter().join(", "), "1, 2, 3"); + assert_eq!( one.iter().join(", "), "1"); + assert_eq!(none.iter().join(", "), ""); +} + +#[test] +fn sorted_by() { + let sc = [3, 4, 1, 2].iter().cloned().sorted_by(|&a, &b| { + a.cmp(&b) + }); + it::assert_equal(sc, vec![1, 2, 3, 4]); + + let v = (0..5).sorted_by(|&a, &b| a.cmp(&b).reverse()); + it::assert_equal(v, vec![4, 3, 2, 1, 0]); +} + +#[test] +fn sorted_by_key() { + let sc = [3, 4, 1, 2].iter().cloned().sorted_by_key(|&x| x); + it::assert_equal(sc, vec![1, 2, 3, 4]); + + let v = (0..5).sorted_by_key(|&x| -x); + it::assert_equal(v, vec![4, 3, 2, 1, 0]); +} + +#[test] +fn test_multipeek() { + let nums = vec![1u8,2,3,4,5]; + + let mp = multipeek(nums.iter().map(|&x| x)); + assert_eq!(nums, mp.collect::>()); + + let mut mp = multipeek(nums.iter().map(|&x| x)); + assert_eq!(mp.peek(), Some(&1)); + assert_eq!(mp.next(), Some(1)); + assert_eq!(mp.peek(), Some(&2)); + assert_eq!(mp.peek(), Some(&3)); + assert_eq!(mp.next(), Some(2)); + assert_eq!(mp.peek(), Some(&3)); + assert_eq!(mp.peek(), Some(&4)); + assert_eq!(mp.peek(), Some(&5)); + assert_eq!(mp.peek(), None); + assert_eq!(mp.next(), Some(3)); + assert_eq!(mp.next(), Some(4)); + assert_eq!(mp.peek(), Some(&5)); + assert_eq!(mp.peek(), None); + assert_eq!(mp.next(), Some(5)); + assert_eq!(mp.next(), None); + assert_eq!(mp.peek(), None); + +} + +#[test] +fn test_multipeek_reset() { + let data = [1, 2, 3, 4]; + + let mut mp = multipeek(cloned(&data)); + assert_eq!(mp.peek(), Some(&1)); + assert_eq!(mp.next(), Some(1)); + assert_eq!(mp.peek(), Some(&2)); + assert_eq!(mp.peek(), Some(&3)); + mp.reset_peek(); + assert_eq!(mp.peek(), Some(&2)); + assert_eq!(mp.next(), Some(2)); +} + +#[test] +fn test_multipeek_peeking_next() { + use crate::it::PeekingNext; + let nums = vec![1u8,2,3,4,5,6,7]; + + let mut mp = multipeek(nums.iter().map(|&x| x)); + assert_eq!(mp.peeking_next(|&x| x != 0), Some(1)); + assert_eq!(mp.next(), Some(2)); + assert_eq!(mp.peek(), Some(&3)); + assert_eq!(mp.peek(), Some(&4)); + assert_eq!(mp.peeking_next(|&x| x == 3), Some(3)); + assert_eq!(mp.peek(), Some(&4)); + assert_eq!(mp.peeking_next(|&x| x != 4), None); + assert_eq!(mp.peeking_next(|&x| x == 4), Some(4)); + assert_eq!(mp.peek(), Some(&5)); + assert_eq!(mp.peek(), Some(&6)); + assert_eq!(mp.peeking_next(|&x| x != 5), None); + assert_eq!(mp.peek(), Some(&7)); + assert_eq!(mp.peeking_next(|&x| x == 5), Some(5)); + assert_eq!(mp.peeking_next(|&x| x == 6), Some(6)); + assert_eq!(mp.peek(), Some(&7)); + assert_eq!(mp.peek(), None); + assert_eq!(mp.next(), Some(7)); + assert_eq!(mp.peek(), None); +} + +#[test] +fn pad_using() { + it::assert_equal((0..0).pad_using(1, |_| 1), 1..2); + + let v: Vec = vec![0, 1, 2]; + let r = v.into_iter().pad_using(5, |n| n); + it::assert_equal(r, vec![0, 1, 2, 3, 4]); + + let v: Vec = vec![0, 1, 2]; + let r = v.into_iter().pad_using(1, |_| panic!()); + it::assert_equal(r, vec![0, 1, 2]); +} + +#[test] +fn group_by() { + for (ch1, sub) in &"AABBCCC".chars().group_by(|&x| x) { + for ch2 in sub { + assert_eq!(ch1, ch2); + } + } + + for (ch1, sub) in &"AAABBBCCCCDDDD".chars().group_by(|&x| x) { + for ch2 in sub { + assert_eq!(ch1, ch2); + if ch1 == 'C' { + break; + } + } + } + + let toupper = |ch: &char| ch.to_uppercase().nth(0).unwrap(); + + // try all possible orderings + for indices in permutohedron::Heap::new(&mut [0, 1, 2, 3]) { + let groups = "AaaBbbccCcDDDD".chars().group_by(&toupper); + let mut subs = groups.into_iter().collect_vec(); + + for &idx in &indices[..] { + let (key, text) = match idx { + 0 => ('A', "Aaa".chars()), + 1 => ('B', "Bbb".chars()), + 2 => ('C', "ccCc".chars()), + 3 => ('D', "DDDD".chars()), + _ => unreachable!(), + }; + assert_eq!(key, subs[idx].0); + it::assert_equal(&mut subs[idx].1, text); + } + } + + let groups = "AAABBBCCCCDDDD".chars().group_by(|&x| x); + let mut subs = groups.into_iter().map(|(_, g)| g).collect_vec(); + + let sd = subs.pop().unwrap(); + let sc = subs.pop().unwrap(); + let sb = subs.pop().unwrap(); + let sa = subs.pop().unwrap(); + for (a, b, c, d) in multizip((sa, sb, sc, sd)) { + assert_eq!(a, 'A'); + assert_eq!(b, 'B'); + assert_eq!(c, 'C'); + assert_eq!(d, 'D'); + } + + // check that the key closure is called exactly n times + { + let mut ntimes = 0; + let text = "AABCCC"; + for (_, sub) in &text.chars().group_by(|&x| { ntimes += 1; x}) { + for _ in sub { + } + } + assert_eq!(ntimes, text.len()); + } + + { + let mut ntimes = 0; + let text = "AABCCC"; + for _ in &text.chars().group_by(|&x| { ntimes += 1; x}) { + } + assert_eq!(ntimes, text.len()); + } + + { + let text = "ABCCCDEEFGHIJJKK"; + let gr = text.chars().group_by(|&x| x); + it::assert_equal(gr.into_iter().flat_map(|(_, sub)| sub), text.chars()); + } +} + +#[test] +fn group_by_lazy_2() { + let data = vec![0, 1]; + let groups = data.iter().group_by(|k| *k); + let gs = groups.into_iter().collect_vec(); + it::assert_equal(data.iter(), gs.into_iter().flat_map(|(_k, g)| g)); + + let data = vec![0, 1, 1, 0, 0]; + let groups = data.iter().group_by(|k| *k); + let mut gs = groups.into_iter().collect_vec(); + gs[1..].reverse(); + it::assert_equal(&[0, 0, 0, 1, 1], gs.into_iter().flat_map(|(_, g)| g)); + + let grouper = data.iter().group_by(|k| *k); + let mut groups = Vec::new(); + for (k, group) in &grouper { + if *k == 1 { + groups.push(group); + } + } + it::assert_equal(&mut groups[0], &[1, 1]); + + let data = vec![0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3]; + let grouper = data.iter().group_by(|k| *k); + let mut groups = Vec::new(); + for (i, (_, group)) in grouper.into_iter().enumerate() { + if i < 2 { + groups.push(group); + } else if i < 4 { + for _ in group { + } + } else { + groups.push(group); + } + } + it::assert_equal(&mut groups[0], &[0, 0, 0]); + it::assert_equal(&mut groups[1], &[1, 1]); + it::assert_equal(&mut groups[2], &[3, 3]); + + // use groups as chunks + let data = vec![0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3]; + let mut i = 0; + let grouper = data.iter().group_by(move |_| { let k = i / 3; i += 1; k }); + for (i, group) in &grouper { + match i { + 0 => it::assert_equal(group, &[0, 0, 0]), + 1 => it::assert_equal(group, &[1, 1, 0]), + 2 => it::assert_equal(group, &[0, 2, 2]), + 3 => it::assert_equal(group, &[3, 3]), + _ => unreachable!(), + } + } +} + +#[test] +fn group_by_lazy_3() { + // test consuming each group on the lap after it was produced + let data = vec![0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2]; + let grouper = data.iter().group_by(|elt| *elt); + let mut last = None; + for (key, group) in &grouper { + if let Some(gr) = last.take() { + for elt in gr { + assert!(elt != key && i32::abs(elt - key) == 1); + } + } + last = Some(group); + } +} + +#[test] +fn chunks() { + let data = vec![0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3]; + let grouper = data.iter().chunks(3); + for (i, chunk) in grouper.into_iter().enumerate() { + match i { + 0 => it::assert_equal(chunk, &[0, 0, 0]), + 1 => it::assert_equal(chunk, &[1, 1, 0]), + 2 => it::assert_equal(chunk, &[0, 2, 2]), + 3 => it::assert_equal(chunk, &[3, 3]), + _ => unreachable!(), + } + } +} + +#[test] +fn concat_empty() { + let data: Vec> = Vec::new(); + assert_eq!(data.into_iter().concat(), Vec::new()) +} + +#[test] +fn concat_non_empty() { + let data = vec![vec![1,2,3], vec![4,5,6], vec![7,8,9]]; + assert_eq!(data.into_iter().concat(), vec![1,2,3,4,5,6,7,8,9]) +} + +#[test] +fn combinations() { + assert!((1..3).combinations(5).next().is_none()); + + let it = (1..3).combinations(2); + it::assert_equal(it, vec![ + vec![1, 2], + ]); + + let it = (1..5).combinations(2); + it::assert_equal(it, vec![ + vec![1, 2], + vec![1, 3], + vec![1, 4], + vec![2, 3], + vec![2, 4], + vec![3, 4], + ]); + + it::assert_equal((0..0).tuple_combinations::<(_, _)>(), >::new()); + it::assert_equal((0..1).tuple_combinations::<(_, _)>(), >::new()); + it::assert_equal((0..2).tuple_combinations::<(_, _)>(), vec![(0, 1)]); + + it::assert_equal((0..0).combinations(2), >>::new()); + it::assert_equal((0..1).combinations(1), vec![vec![0]]); + it::assert_equal((0..2).combinations(1), vec![vec![0], vec![1]]); + it::assert_equal((0..2).combinations(2), vec![vec![0, 1]]); +} + +#[test] +fn combinations_of_too_short() { + for i in 1..10 { + assert!((0..0).combinations(i).next().is_none()); + assert!((0..i - 1).combinations(i).next().is_none()); + } +} + + +#[test] +fn combinations_zero() { + it::assert_equal((1..3).combinations(0), vec![vec![]]); + it::assert_equal((0..0).combinations(0), vec![vec![]]); +} + +#[test] +fn permutations_zero() { + it::assert_equal((1..3).permutations(0), vec![vec![]]); + it::assert_equal((0..0).permutations(0), vec![vec![]]); +} + +#[test] +fn combinations_with_replacement() { + // Pool smaller than n + it::assert_equal((0..1).combinations_with_replacement(2), vec![vec![0, 0]]); + // Pool larger than n + it::assert_equal( + (0..3).combinations_with_replacement(2), + vec![ + vec![0, 0], + vec![0, 1], + vec![0, 2], + vec![1, 1], + vec![1, 2], + vec![2, 2], + ], + ); + // Zero size + it::assert_equal( + (0..3).combinations_with_replacement(0), + vec![vec![]], + ); + // Zero size on empty pool + it::assert_equal( + (0..0).combinations_with_replacement(0), + vec![vec![]], + ); + // Empty pool + it::assert_equal( + (0..0).combinations_with_replacement(2), + >>::new(), + ); +} + +#[test] +fn diff_mismatch() { + let a = vec![1, 2, 3, 4]; + let b = vec![1.0, 5.0, 3.0, 4.0]; + let b_map = b.into_iter().map(|f| f as i32); + let diff = it::diff_with(a.iter(), b_map, |a, b| *a == b); + + assert!(match diff { + Some(it::Diff::FirstMismatch(1, _, from_diff)) => + from_diff.collect::>() == vec![5, 3, 4], + _ => false, + }); +} + +#[test] +fn diff_longer() { + let a = vec![1, 2, 3, 4]; + let b = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; + let b_map = b.into_iter().map(|f| f as i32); + let diff = it::diff_with(a.iter(), b_map, |a, b| *a == b); + + assert!(match diff { + Some(it::Diff::Longer(_, remaining)) => + remaining.collect::>() == vec![5, 6], + _ => false, + }); +} + +#[test] +fn diff_shorter() { + let a = vec![1, 2, 3, 4]; + let b = vec![1.0, 2.0]; + let b_map = b.into_iter().map(|f| f as i32); + let diff = it::diff_with(a.iter(), b_map, |a, b| *a == b); + + assert!(match diff { + Some(it::Diff::Shorter(len, _)) => len == 2, + _ => false, + }); +} + +#[test] +fn minmax() { + use std::cmp::Ordering; + use crate::it::MinMaxResult; + + // A peculiar type: Equality compares both tuple items, but ordering only the + // first item. This is so we can check the stability property easily. + #[derive(Clone, Debug, PartialEq, Eq)] + struct Val(u32, u32); + + impl PartialOrd for Val { + fn partial_cmp(&self, other: &Val) -> Option { + self.0.partial_cmp(&other.0) + } + } + + impl Ord for Val { + fn cmp(&self, other: &Val) -> Ordering { + self.0.cmp(&other.0) + } + } + + assert_eq!(None::>.iter().minmax(), MinMaxResult::NoElements); + + assert_eq!(Some(1u32).iter().minmax(), MinMaxResult::OneElement(&1)); + + let data = vec![Val(0, 1), Val(2, 0), Val(0, 2), Val(1, 0), Val(2, 1)]; + + let minmax = data.iter().minmax(); + assert_eq!(minmax, MinMaxResult::MinMax(&Val(0, 1), &Val(2, 1))); + + let (min, max) = data.iter().minmax_by_key(|v| v.1).into_option().unwrap(); + assert_eq!(min, &Val(2, 0)); + assert_eq!(max, &Val(0, 2)); + + let (min, max) = data.iter().minmax_by(|x, y| x.1.cmp(&y.1)).into_option().unwrap(); + assert_eq!(min, &Val(2, 0)); + assert_eq!(max, &Val(0, 2)); +} + +#[test] +fn format() { + let data = [0, 1, 2, 3]; + let ans1 = "0, 1, 2, 3"; + let ans2 = "0--1--2--3"; + + let t1 = format!("{}", data.iter().format(", ")); + assert_eq!(t1, ans1); + let t2 = format!("{:?}", data.iter().format("--")); + assert_eq!(t2, ans2); + + let dataf = [1.1, 2.71828, -22.]; + let t3 = format!("{:.2e}", dataf.iter().format(", ")); + assert_eq!(t3, "1.10e0, 2.72e0, -2.20e1"); +} + +#[test] +fn while_some() { + let ns = (1..10).map(|x| if x % 5 != 0 { Some(x) } else { None }) + .while_some(); + it::assert_equal(ns, vec![1, 2, 3, 4]); +} + +#[allow(deprecated)] +#[test] +fn fold_while() { + let mut iterations = 0; + let vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let sum = vec.into_iter().fold_while(0, |acc, item| { + iterations += 1; + let new_sum = acc.clone() + item; + if new_sum <= 20 { + FoldWhile::Continue(new_sum) + } else { + FoldWhile::Done(acc) + } + }).into_inner(); + assert_eq!(iterations, 6); + assert_eq!(sum, 15); +} + +#[test] +fn tree_fold1() { + let x = [ + "", + "0", + "0 1 x", + "0 1 x 2 x", + "0 1 x 2 3 x x", + "0 1 x 2 3 x x 4 x", + "0 1 x 2 3 x x 4 5 x x", + "0 1 x 2 3 x x 4 5 x 6 x x", + "0 1 x 2 3 x x 4 5 x 6 7 x x x", + "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 x", + "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x x", + "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 x x", + "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x x", + "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 x x", + "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x x x", + "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x 14 x x x", + "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x 14 15 x x x x", + ]; + for (i, &s) in x.iter().enumerate() { + let expected = if s == "" { None } else { Some(s.to_string()) }; + let num_strings = (0..i).map(|x| x.to_string()); + let actual = num_strings.tree_fold1(|a, b| format!("{} {} x", a, b)); + assert_eq!(actual, expected); + } +} diff --git a/src/rust/vendor/itertools/tests/tuples.rs b/src/rust/vendor/itertools/tests/tuples.rs new file mode 100644 index 000000000..9fc8b3cc7 --- /dev/null +++ b/src/rust/vendor/itertools/tests/tuples.rs @@ -0,0 +1,86 @@ +use itertools::Itertools; + +#[test] +fn tuples() { + let v = [1, 2, 3, 4, 5]; + let mut iter = v.iter().cloned().tuples(); + assert_eq!(Some((1,)), iter.next()); + assert_eq!(Some((2,)), iter.next()); + assert_eq!(Some((3,)), iter.next()); + assert_eq!(Some((4,)), iter.next()); + assert_eq!(Some((5,)), iter.next()); + assert_eq!(None, iter.next()); + assert_eq!(None, iter.into_buffer().next()); + + let mut iter = v.iter().cloned().tuples(); + assert_eq!(Some((1, 2)), iter.next()); + assert_eq!(Some((3, 4)), iter.next()); + assert_eq!(None, iter.next()); + itertools::assert_equal(vec![5], iter.into_buffer()); + + let mut iter = v.iter().cloned().tuples(); + assert_eq!(Some((1, 2, 3)), iter.next()); + assert_eq!(None, iter.next()); + itertools::assert_equal(vec![4, 5], iter.into_buffer()); + + let mut iter = v.iter().cloned().tuples(); + assert_eq!(Some((1, 2, 3, 4)), iter.next()); + assert_eq!(None, iter.next()); + itertools::assert_equal(vec![5], iter.into_buffer()); +} + +#[test] +fn tuple_windows() { + let v = [1, 2, 3, 4, 5]; + + let mut iter = v.iter().cloned().tuple_windows(); + assert_eq!(Some((1,)), iter.next()); + assert_eq!(Some((2,)), iter.next()); + assert_eq!(Some((3,)), iter.next()); + + let mut iter = v.iter().cloned().tuple_windows(); + assert_eq!(Some((1, 2)), iter.next()); + assert_eq!(Some((2, 3)), iter.next()); + assert_eq!(Some((3, 4)), iter.next()); + assert_eq!(Some((4, 5)), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = v.iter().cloned().tuple_windows(); + assert_eq!(Some((1, 2, 3)), iter.next()); + assert_eq!(Some((2, 3, 4)), iter.next()); + assert_eq!(Some((3, 4, 5)), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = v.iter().cloned().tuple_windows(); + assert_eq!(Some((1, 2, 3, 4)), iter.next()); + assert_eq!(Some((2, 3, 4, 5)), iter.next()); + assert_eq!(None, iter.next()); + + let v = [1, 2, 3]; + let mut iter = v.iter().cloned().tuple_windows::<(_, _, _, _)>(); + assert_eq!(None, iter.next()); +} + +#[test] +fn next_tuple() { + let v = [1, 2, 3, 4, 5]; + let mut iter = v.iter(); + assert_eq!(iter.next_tuple().map(|(&x, &y)| (x, y)), Some((1, 2))); + assert_eq!(iter.next_tuple().map(|(&x, &y)| (x, y)), Some((3, 4))); + assert_eq!(iter.next_tuple::<(_, _)>(), None); +} + +#[test] +fn collect_tuple() { + let v = [1, 2]; + let iter = v.iter().cloned(); + assert_eq!(iter.collect_tuple(), Some((1, 2))); + + let v = [1]; + let iter = v.iter().cloned(); + assert_eq!(iter.collect_tuple::<(_, _)>(), None); + + let v = [1, 2, 3]; + let iter = v.iter().cloned(); + assert_eq!(iter.collect_tuple::<(_, _)>(), None); +} diff --git a/src/rust/vendor/itertools/tests/zip.rs b/src/rust/vendor/itertools/tests/zip.rs new file mode 100644 index 000000000..b1af52c9c --- /dev/null +++ b/src/rust/vendor/itertools/tests/zip.rs @@ -0,0 +1,63 @@ +use itertools::Itertools; +use itertools::EitherOrBoth::{Both, Left, Right}; +use itertools::free::zip_eq; + +#[test] +fn zip_longest_fused() { + let a = [Some(1), None, Some(3), Some(4)]; + let b = [1, 2, 3]; + + let unfused = a.iter().batching(|it| *it.next().unwrap()) + .zip_longest(b.iter().cloned()); + itertools::assert_equal(unfused, + vec![Both(1, 1), Right(2), Right(3)]); +} + +#[test] +fn test_zip_longest_size_hint() { + let c = (1..10).cycle(); + let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let v2 = &[10, 11, 12]; + + assert_eq!(c.zip_longest(v.iter()).size_hint(), (std::usize::MAX, None)); + + assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10))); +} + +#[test] +fn test_double_ended_zip_longest() { + let xs = [1, 2, 3, 4, 5, 6]; + let ys = [1, 2, 3, 7]; + let a = xs.iter().map(|&x| x); + let b = ys.iter().map(|&x| x); + let mut it = a.zip_longest(b); + assert_eq!(it.next(), Some(Both(1, 1))); + assert_eq!(it.next(), Some(Both(2, 2))); + assert_eq!(it.next_back(), Some(Left(6))); + assert_eq!(it.next_back(), Some(Left(5))); + assert_eq!(it.next_back(), Some(Both(4, 7))); + assert_eq!(it.next(), Some(Both(3, 3))); + assert_eq!(it.next(), None); +} + + +#[should_panic] +#[test] +fn zip_eq_panic1() +{ + let a = [1, 2]; + let b = [1, 2, 3]; + + zip_eq(&a, &b).count(); +} + +#[should_panic] +#[test] +fn zip_eq_panic2() +{ + let a: [i32; 0] = []; + let b = [1, 2, 3]; + + zip_eq(&a, &b).count(); +} + diff --git a/src/rust/vendor/prost-derive/.cargo-checksum.json b/src/rust/vendor/prost-derive/.cargo-checksum.json new file mode 100644 index 000000000..4f48cb638 --- /dev/null +++ b/src/rust/vendor/prost-derive/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"f7856f8508793ba04f74e177edd8d87e8268c772452f9e0ddb6ffaedbb899cf5","README.md":"6c67fa1e48f14adfaf834f520f798ddfb79f90804f46cc215ee391a7d57913a4","src/field/group.rs":"dfd31b34008741abc857dc11362c11a06afd8eddceb62924443bf2bea117460a","src/field/map.rs":"69e1fa14cfeb4d4407b9c343a2a72b4ba68c3ecb7af912965a63b50e91dd61fb","src/field/message.rs":"fb910a563eba0b0c68a7a3855f7877535931faef4d788b05a3402f0cdd037e3e","src/field/mod.rs":"b14fc0c6f5240c0e6a4cbae065bf2a46b8b9f86673a06665e24a7681b5e88b44","src/field/oneof.rs":"4fc488445b05e464070fadd8799cafb806db5c23d1494c4300cb293394863012","src/field/scalar.rs":"6fac28eadf454aa10f5e5654222ce8e65b2a469b4b5b9ae558943649e1c1a2d2","src/lib.rs":"a474386174b423a040e9651cdb6a24a92ad96e4bebb03d2806c0a9d8eb2b01af"},"package":null} \ No newline at end of file diff --git a/src/rust/vendor/prost-derive/Cargo.toml b/src/rust/vendor/prost-derive/Cargo.toml new file mode 100644 index 000000000..1fec0726b --- /dev/null +++ b/src/rust/vendor/prost-derive/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "prost-derive" +version = "0.6.1" +authors = ["Dan Burkert "] +license = "Apache-2.0" +repository = "https://github.com/danburkert/prost" +documentation = "https://docs.rs/prost-derive" +readme = "README.md" +description = "A Protocol Buffers implementation for the Rust Language." +edition = "2018" + +[lib] +proc_macro = true + +[dependencies] +anyhow = "1" +itertools = "0.9" +proc-macro2 = "1" +quote = "1" +syn = { version = "1", features = [ "extra-traits" ] } diff --git a/src/rust/vendor/prost-derive/README.md b/src/rust/vendor/prost-derive/README.md new file mode 100644 index 000000000..a51050e7e --- /dev/null +++ b/src/rust/vendor/prost-derive/README.md @@ -0,0 +1,16 @@ +[![Documentation](https://docs.rs/prost-derive/badge.svg)](https://docs.rs/prost-derive/) +[![Crate](https://img.shields.io/crates/v/prost-derive.svg)](https://crates.io/crates/prost-derive) + +# prost-derive + +`prost-derive` handles generating encoding and decoding implementations for Rust +types annotated with `prost` annotation. For the most part, users of `prost` +shouldn't need to interact with `prost-derive` directly. + +## License + +`prost-derive` is distributed under the terms of the Apache License (Version 2.0). + +See [LICENSE](../LICENSE) for details. + +Copyright 2017 Dan Burkert diff --git a/src/rust/vendor/prost-derive/src/field/group.rs b/src/rust/vendor/prost-derive/src/field/group.rs new file mode 100644 index 000000000..639612880 --- /dev/null +++ b/src/rust/vendor/prost-derive/src/field/group.rs @@ -0,0 +1,134 @@ +use anyhow::{bail, Error}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::Meta; + +use crate::field::{set_bool, set_option, tag_attr, word_attr, Label}; + +#[derive(Clone)] +pub struct Field { + pub label: Label, + pub tag: u32, +} + +impl Field { + pub fn new(attrs: &[Meta], inferred_tag: Option) -> Result, Error> { + let mut group = false; + let mut label = None; + let mut tag = None; + let mut boxed = false; + + let mut unknown_attrs = Vec::new(); + + for attr in attrs { + if word_attr("group", attr) { + set_bool(&mut group, "duplicate group attributes")?; + } else if word_attr("boxed", attr) { + set_bool(&mut boxed, "duplicate boxed attributes")?; + } else if let Some(t) = tag_attr(attr)? { + set_option(&mut tag, t, "duplicate tag attributes")?; + } else if let Some(l) = Label::from_attr(attr) { + set_option(&mut label, l, "duplicate label attributes")?; + } else { + unknown_attrs.push(attr); + } + } + + if !group { + return Ok(None); + } + + match unknown_attrs.len() { + 0 => (), + 1 => bail!("unknown attribute for group field: {:?}", unknown_attrs[0]), + _ => bail!("unknown attributes for group field: {:?}", unknown_attrs), + } + + let tag = match tag.or(inferred_tag) { + Some(tag) => tag, + None => bail!("group field is missing a tag attribute"), + }; + + Ok(Some(Field { + label: label.unwrap_or(Label::Optional), + tag, + })) + } + + pub fn new_oneof(attrs: &[Meta]) -> Result, Error> { + if let Some(mut field) = Field::new(attrs, None)? { + if let Some(attr) = attrs.iter().find(|attr| Label::from_attr(attr).is_some()) { + bail!( + "invalid attribute for oneof field: {}", + attr.path().into_token_stream() + ); + } + field.label = Label::Required; + Ok(Some(field)) + } else { + Ok(None) + } + } + + pub fn encode(&self, ident: TokenStream) -> TokenStream { + let tag = self.tag; + match self.label { + Label::Optional => quote! { + if let Some(ref msg) = #ident { + ::prost::encoding::group::encode(#tag, msg, buf); + } + }, + Label::Required => quote! { + ::prost::encoding::group::encode(#tag, &#ident, buf); + }, + Label::Repeated => quote! { + for msg in &#ident { + ::prost::encoding::group::encode(#tag, msg, buf); + } + }, + } + } + + pub fn merge(&self, ident: TokenStream) -> TokenStream { + match self.label { + Label::Optional => quote! { + ::prost::encoding::group::merge( + tag, + wire_type, + #ident.get_or_insert_with(Default::default), + buf, + ctx, + ) + }, + Label::Required => quote! { + ::prost::encoding::group::merge(tag, wire_type, #ident, buf, ctx) + }, + Label::Repeated => quote! { + ::prost::encoding::group::merge_repeated(tag, wire_type, #ident, buf, ctx) + }, + } + } + + pub fn encoded_len(&self, ident: TokenStream) -> TokenStream { + let tag = self.tag; + match self.label { + Label::Optional => quote! { + #ident.as_ref().map_or(0, |msg| ::prost::encoding::group::encoded_len(#tag, msg)) + }, + Label::Required => quote! { + ::prost::encoding::group::encoded_len(#tag, &#ident) + }, + Label::Repeated => quote! { + ::prost::encoding::group::encoded_len_repeated(#tag, &#ident) + }, + } + } + + pub fn clear(&self, ident: TokenStream) -> TokenStream { + match self.label { + Label::Optional => quote!(#ident = ::core::option::Option::None), + Label::Required => quote!(#ident.clear()), + Label::Repeated => quote!(#ident.clear()), + } + } +} diff --git a/src/rust/vendor/prost-derive/src/field/map.rs b/src/rust/vendor/prost-derive/src/field/map.rs new file mode 100644 index 000000000..1228a6fae --- /dev/null +++ b/src/rust/vendor/prost-derive/src/field/map.rs @@ -0,0 +1,394 @@ +use anyhow::{bail, Error}; +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::{Ident, Lit, Meta, MetaNameValue, NestedMeta}; + +use crate::field::{scalar, set_option, tag_attr}; + +#[derive(Clone, Debug)] +pub enum MapTy { + HashMap, + BTreeMap, +} + +impl MapTy { + fn from_str(s: &str) -> Option { + match s { + "map" | "hash_map" => Some(MapTy::HashMap), + "btree_map" => Some(MapTy::BTreeMap), + _ => None, + } + } + + fn module(&self) -> Ident { + match *self { + MapTy::HashMap => Ident::new("hash_map", Span::call_site()), + MapTy::BTreeMap => Ident::new("btree_map", Span::call_site()), + } + } + + fn lib(&self) -> TokenStream { + match self { + MapTy::HashMap => quote! { std }, + MapTy::BTreeMap => quote! { prost::alloc }, + } + } +} + +fn fake_scalar(ty: scalar::Ty) -> scalar::Field { + let kind = scalar::Kind::Plain(scalar::DefaultValue::new(&ty)); + scalar::Field { + ty, + kind, + tag: 0, // Not used here + } +} + +#[derive(Clone)] +pub struct Field { + pub map_ty: MapTy, + pub key_ty: scalar::Ty, + pub value_ty: ValueTy, + pub tag: u32, +} + +impl Field { + pub fn new(attrs: &[Meta], inferred_tag: Option) -> Result, Error> { + let mut types = None; + let mut tag = None; + + for attr in attrs { + if let Some(t) = tag_attr(attr)? { + set_option(&mut tag, t, "duplicate tag attributes")?; + } else if let Some(map_ty) = attr + .path() + .get_ident() + .and_then(|i| MapTy::from_str(&i.to_string())) + { + let (k, v): (String, String) = match &*attr { + Meta::NameValue(MetaNameValue { + lit: Lit::Str(lit), .. + }) => { + let items = lit.value(); + let mut items = items.split(',').map(ToString::to_string); + let k = items.next().unwrap(); + let v = match items.next() { + Some(k) => k, + None => bail!("invalid map attribute: must have key and value types"), + }; + if items.next().is_some() { + bail!("invalid map attribute: {:?}", attr); + } + (k, v) + } + Meta::List(meta_list) => { + // TODO(rustlang/rust#23121): slice pattern matching would make this much nicer. + if meta_list.nested.len() != 2 { + bail!("invalid map attribute: must contain key and value types"); + } + let k = match &meta_list.nested[0] { + NestedMeta::Meta(Meta::Path(k)) if k.get_ident().is_some() => { + k.get_ident().unwrap().to_string() + } + _ => bail!("invalid map attribute: key must be an identifier"), + }; + let v = match &meta_list.nested[1] { + NestedMeta::Meta(Meta::Path(v)) if v.get_ident().is_some() => { + v.get_ident().unwrap().to_string() + } + _ => bail!("invalid map attribute: value must be an identifier"), + }; + (k, v) + } + _ => return Ok(None), + }; + set_option( + &mut types, + (map_ty, key_ty_from_str(&k)?, ValueTy::from_str(&v)?), + "duplicate map type attribute", + )?; + } else { + return Ok(None); + } + } + + Ok(match (types, tag.or(inferred_tag)) { + (Some((map_ty, key_ty, value_ty)), Some(tag)) => Some(Field { + map_ty, + key_ty, + value_ty, + tag, + }), + _ => None, + }) + } + + pub fn new_oneof(attrs: &[Meta]) -> Result, Error> { + Field::new(attrs, None) + } + + /// Returns a statement which encodes the map field. + pub fn encode(&self, ident: TokenStream) -> TokenStream { + let tag = self.tag; + let key_mod = self.key_ty.module(); + let ke = quote!(::prost::encoding::#key_mod::encode); + let kl = quote!(::prost::encoding::#key_mod::encoded_len); + let module = self.map_ty.module(); + match &self.value_ty { + ValueTy::Scalar(scalar::Ty::Enumeration(ty)) => { + let default = quote!(#ty::default() as i32); + quote! { + ::prost::encoding::#module::encode_with_default( + #ke, + #kl, + ::prost::encoding::int32::encode, + ::prost::encoding::int32::encoded_len, + &(#default), + #tag, + &#ident, + buf, + ); + } + } + ValueTy::Scalar(value_ty) => { + let val_mod = value_ty.module(); + let ve = quote!(::prost::encoding::#val_mod::encode); + let vl = quote!(::prost::encoding::#val_mod::encoded_len); + quote! { + ::prost::encoding::#module::encode( + #ke, + #kl, + #ve, + #vl, + #tag, + &#ident, + buf, + ); + } + } + ValueTy::Message => quote! { + ::prost::encoding::#module::encode( + #ke, + #kl, + ::prost::encoding::message::encode, + ::prost::encoding::message::encoded_len, + #tag, + &#ident, + buf, + ); + }, + } + } + + /// Returns an expression which evaluates to the result of merging a decoded key value pair + /// into the map. + pub fn merge(&self, ident: TokenStream) -> TokenStream { + let key_mod = self.key_ty.module(); + let km = quote!(::prost::encoding::#key_mod::merge); + let module = self.map_ty.module(); + match &self.value_ty { + ValueTy::Scalar(scalar::Ty::Enumeration(ty)) => { + let default = quote!(#ty::default() as i32); + quote! { + ::prost::encoding::#module::merge_with_default( + #km, + ::prost::encoding::int32::merge, + #default, + &mut #ident, + buf, + ctx, + ) + } + } + ValueTy::Scalar(value_ty) => { + let val_mod = value_ty.module(); + let vm = quote!(::prost::encoding::#val_mod::merge); + quote!(::prost::encoding::#module::merge(#km, #vm, &mut #ident, buf, ctx)) + } + ValueTy::Message => quote! { + ::prost::encoding::#module::merge( + #km, + ::prost::encoding::message::merge, + &mut #ident, + buf, + ctx, + ) + }, + } + } + + /// Returns an expression which evaluates to the encoded length of the map. + pub fn encoded_len(&self, ident: TokenStream) -> TokenStream { + let tag = self.tag; + let key_mod = self.key_ty.module(); + let kl = quote!(::prost::encoding::#key_mod::encoded_len); + let module = self.map_ty.module(); + match &self.value_ty { + ValueTy::Scalar(scalar::Ty::Enumeration(ty)) => { + let default = quote!(#ty::default() as i32); + quote! { + ::prost::encoding::#module::encoded_len_with_default( + #kl, + ::prost::encoding::int32::encoded_len, + &(#default), + #tag, + &#ident, + ) + } + } + ValueTy::Scalar(value_ty) => { + let val_mod = value_ty.module(); + let vl = quote!(::prost::encoding::#val_mod::encoded_len); + quote!(::prost::encoding::#module::encoded_len(#kl, #vl, #tag, &#ident)) + } + ValueTy::Message => quote! { + ::prost::encoding::#module::encoded_len( + #kl, + ::prost::encoding::message::encoded_len, + #tag, + &#ident, + ) + }, + } + } + + pub fn clear(&self, ident: TokenStream) -> TokenStream { + quote!(#ident.clear()) + } + + /// Returns methods to embed in the message. + pub fn methods(&self, ident: &Ident) -> Option { + if let ValueTy::Scalar(scalar::Ty::Enumeration(ty)) = &self.value_ty { + let key_ty = self.key_ty.rust_type(); + let key_ref_ty = self.key_ty.rust_ref_type(); + + let get = Ident::new(&format!("get_{}", ident), Span::call_site()); + let insert = Ident::new(&format!("insert_{}", ident), Span::call_site()); + let take_ref = if self.key_ty.is_numeric() { + quote!(&) + } else { + quote!() + }; + + let get_doc = format!( + "Returns the enum value for the corresponding key in `{}`, \ + or `None` if the entry does not exist or it is not a valid enum value.", + ident, + ); + let insert_doc = format!("Inserts a key value pair into `{}`.", ident); + Some(quote! { + #[doc=#get_doc] + pub fn #get(&self, key: #key_ref_ty) -> ::core::option::Option<#ty> { + self.#ident.get(#take_ref key).cloned().and_then(#ty::from_i32) + } + #[doc=#insert_doc] + pub fn #insert(&mut self, key: #key_ty, value: #ty) -> ::core::option::Option<#ty> { + self.#ident.insert(key, value as i32).and_then(#ty::from_i32) + } + }) + } else { + None + } + } + + /// Returns a newtype wrapper around the map, implementing nicer Debug + /// + /// The Debug tries to convert any enumerations met into the variants if possible, instead of + /// outputting the raw numbers. + pub fn debug(&self, wrapper_name: TokenStream) -> TokenStream { + let type_name = match self.map_ty { + MapTy::HashMap => Ident::new("HashMap", Span::call_site()), + MapTy::BTreeMap => Ident::new("BTreeMap", Span::call_site()), + }; + + // A fake field for generating the debug wrapper + let key_wrapper = fake_scalar(self.key_ty.clone()).debug(quote!(KeyWrapper)); + let key = self.key_ty.rust_type(); + let value_wrapper = self.value_ty.debug(); + let libname = self.map_ty.lib(); + let fmt = quote! { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + #key_wrapper + #value_wrapper + let mut builder = f.debug_map(); + for (k, v) in self.0 { + builder.entry(&KeyWrapper(k), &ValueWrapper(v)); + } + builder.finish() + } + }; + match &self.value_ty { + ValueTy::Scalar(ty) => { + let value = ty.rust_type(); + quote! { + struct #wrapper_name<'a>(&'a ::#libname::collections::#type_name<#key, #value>); + impl<'a> ::core::fmt::Debug for #wrapper_name<'a> { + #fmt + } + } + } + ValueTy::Message => quote! { + struct #wrapper_name<'a, V: 'a>(&'a ::#libname::collections::#type_name<#key, V>); + impl<'a, V> ::core::fmt::Debug for #wrapper_name<'a, V> + where + V: ::core::fmt::Debug + 'a, + { + #fmt + } + }, + } + } +} + +fn key_ty_from_str(s: &str) -> Result { + let ty = scalar::Ty::from_str(s)?; + match ty { + scalar::Ty::Int32 + | scalar::Ty::Int64 + | scalar::Ty::Uint32 + | scalar::Ty::Uint64 + | scalar::Ty::Sint32 + | scalar::Ty::Sint64 + | scalar::Ty::Fixed32 + | scalar::Ty::Fixed64 + | scalar::Ty::Sfixed32 + | scalar::Ty::Sfixed64 + | scalar::Ty::Bool + | scalar::Ty::String => Ok(ty), + _ => bail!("invalid map key type: {}", s), + } +} + +/// A map value type. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ValueTy { + Scalar(scalar::Ty), + Message, +} + +impl ValueTy { + fn from_str(s: &str) -> Result { + if let Ok(ty) = scalar::Ty::from_str(s) { + Ok(ValueTy::Scalar(ty)) + } else if s.trim() == "message" { + Ok(ValueTy::Message) + } else { + bail!("invalid map value type: {}", s); + } + } + + /// Returns a newtype wrapper around the ValueTy for nicer debug. + /// + /// If the contained value is enumeration, it tries to convert it to the variant. If not, it + /// just forwards the implementation. + fn debug(&self) -> TokenStream { + match self { + ValueTy::Scalar(ty) => fake_scalar(ty.clone()).debug(quote!(ValueWrapper)), + ValueTy::Message => quote!( + fn ValueWrapper(v: T) -> T { + v + } + ), + } + } +} diff --git a/src/rust/vendor/prost-derive/src/field/message.rs b/src/rust/vendor/prost-derive/src/field/message.rs new file mode 100644 index 000000000..1ff7c3798 --- /dev/null +++ b/src/rust/vendor/prost-derive/src/field/message.rs @@ -0,0 +1,134 @@ +use anyhow::{bail, Error}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::Meta; + +use crate::field::{set_bool, set_option, tag_attr, word_attr, Label}; + +#[derive(Clone)] +pub struct Field { + pub label: Label, + pub tag: u32, +} + +impl Field { + pub fn new(attrs: &[Meta], inferred_tag: Option) -> Result, Error> { + let mut message = false; + let mut label = None; + let mut tag = None; + let mut boxed = false; + + let mut unknown_attrs = Vec::new(); + + for attr in attrs { + if word_attr("message", attr) { + set_bool(&mut message, "duplicate message attribute")?; + } else if word_attr("boxed", attr) { + set_bool(&mut boxed, "duplicate boxed attribute")?; + } else if let Some(t) = tag_attr(attr)? { + set_option(&mut tag, t, "duplicate tag attributes")?; + } else if let Some(l) = Label::from_attr(attr) { + set_option(&mut label, l, "duplicate label attributes")?; + } else { + unknown_attrs.push(attr); + } + } + + if !message { + return Ok(None); + } + + match unknown_attrs.len() { + 0 => (), + 1 => bail!( + "unknown attribute for message field: {:?}", + unknown_attrs[0] + ), + _ => bail!("unknown attributes for message field: {:?}", unknown_attrs), + } + + let tag = match tag.or(inferred_tag) { + Some(tag) => tag, + None => bail!("message field is missing a tag attribute"), + }; + + Ok(Some(Field { + label: label.unwrap_or(Label::Optional), + tag, + })) + } + + pub fn new_oneof(attrs: &[Meta]) -> Result, Error> { + if let Some(mut field) = Field::new(attrs, None)? { + if let Some(attr) = attrs.iter().find(|attr| Label::from_attr(attr).is_some()) { + bail!( + "invalid attribute for oneof field: {}", + attr.path().into_token_stream() + ); + } + field.label = Label::Required; + Ok(Some(field)) + } else { + Ok(None) + } + } + + pub fn encode(&self, ident: TokenStream) -> TokenStream { + let tag = self.tag; + match self.label { + Label::Optional => quote! { + if let Some(ref msg) = #ident { + ::prost::encoding::message::encode(#tag, msg, buf); + } + }, + Label::Required => quote! { + ::prost::encoding::message::encode(#tag, &#ident, buf); + }, + Label::Repeated => quote! { + for msg in &#ident { + ::prost::encoding::message::encode(#tag, msg, buf); + } + }, + } + } + + pub fn merge(&self, ident: TokenStream) -> TokenStream { + match self.label { + Label::Optional => quote! { + ::prost::encoding::message::merge(wire_type, + #ident.get_or_insert_with(Default::default), + buf, + ctx) + }, + Label::Required => quote! { + ::prost::encoding::message::merge(wire_type, #ident, buf, ctx) + }, + Label::Repeated => quote! { + ::prost::encoding::message::merge_repeated(wire_type, #ident, buf, ctx) + }, + } + } + + pub fn encoded_len(&self, ident: TokenStream) -> TokenStream { + let tag = self.tag; + match self.label { + Label::Optional => quote! { + #ident.as_ref().map_or(0, |msg| ::prost::encoding::message::encoded_len(#tag, msg)) + }, + Label::Required => quote! { + ::prost::encoding::message::encoded_len(#tag, &#ident) + }, + Label::Repeated => quote! { + ::prost::encoding::message::encoded_len_repeated(#tag, &#ident) + }, + } + } + + pub fn clear(&self, ident: TokenStream) -> TokenStream { + match self.label { + Label::Optional => quote!(#ident = ::core::option::Option::None), + Label::Required => quote!(#ident.clear()), + Label::Repeated => quote!(#ident.clear()), + } + } +} diff --git a/src/rust/vendor/prost-derive/src/field/mod.rs b/src/rust/vendor/prost-derive/src/field/mod.rs new file mode 100644 index 000000000..9e2e70c4c --- /dev/null +++ b/src/rust/vendor/prost-derive/src/field/mod.rs @@ -0,0 +1,366 @@ +mod group; +mod map; +mod message; +mod oneof; +mod scalar; + +use std::fmt; +use std::slice; + +use anyhow::{bail, Error}; +use proc_macro2::TokenStream; +use quote::quote; +use syn::{Attribute, Ident, Lit, LitBool, Meta, MetaList, MetaNameValue, NestedMeta}; + +#[derive(Clone)] +pub enum Field { + /// A scalar field. + Scalar(scalar::Field), + /// A message field. + Message(message::Field), + /// A map field. + Map(map::Field), + /// A oneof field. + Oneof(oneof::Field), + /// A group field. + Group(group::Field), +} + +impl Field { + /// Creates a new `Field` from an iterator of field attributes. + /// + /// If the meta items are invalid, an error will be returned. + /// If the field should be ignored, `None` is returned. + pub fn new(attrs: Vec, inferred_tag: Option) -> Result, Error> { + let attrs = prost_attrs(attrs)?; + + // TODO: check for ignore attribute. + + let field = if let Some(field) = scalar::Field::new(&attrs, inferred_tag)? { + Field::Scalar(field) + } else if let Some(field) = message::Field::new(&attrs, inferred_tag)? { + Field::Message(field) + } else if let Some(field) = map::Field::new(&attrs, inferred_tag)? { + Field::Map(field) + } else if let Some(field) = oneof::Field::new(&attrs)? { + Field::Oneof(field) + } else if let Some(field) = group::Field::new(&attrs, inferred_tag)? { + Field::Group(field) + } else { + bail!("no type attribute"); + }; + + Ok(Some(field)) + } + + /// Creates a new oneof `Field` from an iterator of field attributes. + /// + /// If the meta items are invalid, an error will be returned. + /// If the field should be ignored, `None` is returned. + pub fn new_oneof(attrs: Vec) -> Result, Error> { + let attrs = prost_attrs(attrs)?; + + // TODO: check for ignore attribute. + + let field = if let Some(field) = scalar::Field::new_oneof(&attrs)? { + Field::Scalar(field) + } else if let Some(field) = message::Field::new_oneof(&attrs)? { + Field::Message(field) + } else if let Some(field) = map::Field::new_oneof(&attrs)? { + Field::Map(field) + } else if let Some(field) = group::Field::new_oneof(&attrs)? { + Field::Group(field) + } else { + bail!("no type attribute for oneof field"); + }; + + Ok(Some(field)) + } + + pub fn tags(&self) -> Vec { + match *self { + Field::Scalar(ref scalar) => vec![scalar.tag], + Field::Message(ref message) => vec![message.tag], + Field::Map(ref map) => vec![map.tag], + Field::Oneof(ref oneof) => oneof.tags.clone(), + Field::Group(ref group) => vec![group.tag], + } + } + + /// Returns a statement which encodes the field. + pub fn encode(&self, ident: TokenStream) -> TokenStream { + match *self { + Field::Scalar(ref scalar) => scalar.encode(ident), + Field::Message(ref message) => message.encode(ident), + Field::Map(ref map) => map.encode(ident), + Field::Oneof(ref oneof) => oneof.encode(ident), + Field::Group(ref group) => group.encode(ident), + } + } + + /// Returns an expression which evaluates to the result of merging a decoded + /// value into the field. + pub fn merge(&self, ident: TokenStream) -> TokenStream { + match *self { + Field::Scalar(ref scalar) => scalar.merge(ident), + Field::Message(ref message) => message.merge(ident), + Field::Map(ref map) => map.merge(ident), + Field::Oneof(ref oneof) => oneof.merge(ident), + Field::Group(ref group) => group.merge(ident), + } + } + + /// Returns an expression which evaluates to the encoded length of the field. + pub fn encoded_len(&self, ident: TokenStream) -> TokenStream { + match *self { + Field::Scalar(ref scalar) => scalar.encoded_len(ident), + Field::Map(ref map) => map.encoded_len(ident), + Field::Message(ref msg) => msg.encoded_len(ident), + Field::Oneof(ref oneof) => oneof.encoded_len(ident), + Field::Group(ref group) => group.encoded_len(ident), + } + } + + /// Returns a statement which clears the field. + pub fn clear(&self, ident: TokenStream) -> TokenStream { + match *self { + Field::Scalar(ref scalar) => scalar.clear(ident), + Field::Message(ref message) => message.clear(ident), + Field::Map(ref map) => map.clear(ident), + Field::Oneof(ref oneof) => oneof.clear(ident), + Field::Group(ref group) => group.clear(ident), + } + } + + pub fn default(&self) -> TokenStream { + match *self { + Field::Scalar(ref scalar) => scalar.default(), + _ => quote!(::core::default::Default::default()), + } + } + + /// Produces the fragment implementing debug for the given field. + pub fn debug(&self, ident: TokenStream) -> TokenStream { + match *self { + Field::Scalar(ref scalar) => { + let wrapper = scalar.debug(quote!(ScalarWrapper)); + quote! { + { + #wrapper + ScalarWrapper(&#ident) + } + } + } + Field::Map(ref map) => { + let wrapper = map.debug(quote!(MapWrapper)); + quote! { + { + #wrapper + MapWrapper(&#ident) + } + } + } + _ => quote!(&#ident), + } + } + + pub fn methods(&self, ident: &Ident) -> Option { + match *self { + Field::Scalar(ref scalar) => scalar.methods(ident), + Field::Map(ref map) => map.methods(ident), + _ => None, + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Label { + /// An optional field. + Optional, + /// A required field. + Required, + /// A repeated field. + Repeated, +} + +impl Label { + fn as_str(self) -> &'static str { + match self { + Label::Optional => "optional", + Label::Required => "required", + Label::Repeated => "repeated", + } + } + + fn variants() -> slice::Iter<'static, Label> { + const VARIANTS: &[Label] = &[Label::Optional, Label::Required, Label::Repeated]; + VARIANTS.iter() + } + + /// Parses a string into a field label. + /// If the string doesn't match a field label, `None` is returned. + fn from_attr(attr: &Meta) -> Option