From f854f34a502c358b0f6826ea3ebf40fb7f146de1 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Fri, 17 Jan 2025 23:01:48 +0100 Subject: Do not include GCC source code in source tarballs The licensing story is unclear, it makes the archive much larger, and we should not need it for building anything in the tarballs (yet). --- src/bootstrap/src/core/build_steps/dist.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index afa409aa835..87f48331bfe 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1011,7 +1011,18 @@ impl Step for PlainSourceTarball { ]; let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"]; - copy_src_dirs(builder, &builder.src, &src_dirs, &[], plain_dst_src); + copy_src_dirs( + builder, + &builder.src, + &src_dirs, + &[ + // We don't currently use the GCC source code for building any official components, + // it is very big, and has unclear licensing implications due to being GPL licensed. + // We thus exclude it from the source tarball from now. + "src/gcc", + ], + plain_dst_src, + ); // Copy the files normally for item in &src_files { -- cgit 1.4.1-3-g733a5 From 903cddb392bc9a5bc43194bcbb8b031f2fcc2c56 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 19 Jan 2025 12:50:49 +0300 Subject: make it possible to use ci-rustc on tarball sources Previously, bootstrap was using `Config::last_modified_commit` unconditionally to figure the commit has to download precompiled rustc artifact from CI, which was leading builds to fail on tarball sources as `Config::last_modified_commit` requires `git` to be present in the project source. This change makes bootstrap to call `Config::last_modified_commit` only when it's running on git-managed source and read `git-commit-hash` file otherwise. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 36 +++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 026380a46c6..aeaab1a5cf7 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2873,21 +2873,26 @@ impl Config { allowed_paths.push(":!library"); } - // Look for a version to compare to based on the current commit. - // Only commits merged by bors will have CI artifacts. - let commit = match self.last_modified_commit(&allowed_paths, "download-rustc", if_unchanged) - { - Some(commit) => commit, - None => { - if if_unchanged { - return None; + let commit = if self.rust_info.is_managed_git_subrepository() { + // Look for a version to compare to based on the current commit. + // Only commits merged by bors will have CI artifacts. + match self.last_modified_commit(&allowed_paths, "download-rustc", if_unchanged) { + Some(commit) => commit, + None => { + if if_unchanged { + return None; + } + println!("ERROR: could not find commit hash for downloading rustc"); + println!("HELP: maybe your repository history is too shallow?"); + println!("HELP: consider setting `rust.download-rustc=false` in config.toml"); + println!("HELP: or fetch enough history to include one upstream commit"); + crate::exit!(1); } - println!("ERROR: could not find commit hash for downloading rustc"); - println!("HELP: maybe your repository history is too shallow?"); - println!("HELP: consider setting `rust.download-rustc=false` in config.toml"); - println!("HELP: or fetch enough history to include one upstream commit"); - crate::exit!(1); } + } else { + channel::read_commit_info_file(&self.src) + .map(|info| info.sha.trim().to_owned()) + .expect("git-commit-info is missing in the project root") }; if CiEnv::is_ci() && { @@ -2969,6 +2974,11 @@ impl Config { option_name: &str, if_unchanged: bool, ) -> Option { + assert!( + self.rust_info.is_managed_git_subrepository(), + "Can't run `Config::last_modified_commit` on a non-git source." + ); + // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap(); -- cgit 1.4.1-3-g733a5 From 242b0e32b6281d435b17d8e672885b1d4433b11a Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Sun, 19 Jan 2025 12:30:12 +0100 Subject: CI: split x86_64-msvc job using windows 2025 --- src/bootstrap/mk/Makefile.in | 8 ++------ src/ci/github-actions/jobs.yml | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 11 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 082b7431440..275c0e803cb 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -106,14 +106,10 @@ STAGE_2_TEST_SET2 := test --stage 2 --skip=tests --skip=coverage-map --skip=cove # this intentionally doesn't use `$(BOOTSTRAP)` so we can test the shebang on Windows ci-msvc-py: - $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 tidy -ci-msvc-ps1: - $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 --skip tidy -ci-msvc: ci-msvc-py ci-msvc-ps1 -ci-msvc-py-set1: $(Q)$(CFG_SRC_DIR)/x.py $(STAGE_2_TEST_SET1) -ci-msvc-ps1-set2: +ci-msvc-ps1: $(Q)$(CFG_SRC_DIR)/x.ps1 $(STAGE_2_TEST_SET2) +ci-msvc: ci-msvc-py ci-msvc-ps1 ## MingW native builders diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 799ea3e9ad2..c5b33a45db7 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -35,6 +35,10 @@ runners: os: windows-2022 <<: *base-job + - &job-windows-25 + os: windows-2025 + <<: *base-job + - &job-windows-8c os: windows-2022-8core-32gb <<: *base-job @@ -442,23 +446,29 @@ auto: # Windows Builders # ###################### - - name: x86_64-msvc + - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler - SCRIPT: make ci-msvc - <<: *job-windows-8c + SCRIPT: make ci-msvc-py + <<: *job-windows-25 + + - name: x86_64-msvc-2 + env: + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler + SCRIPT: make ci-msvc-ps1 + <<: *job-windows-25 # i686-msvc is split into two jobs to run tests in parallel. - name: i686-msvc-1 env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make ci-msvc-py-set1 + SCRIPT: make ci-msvc-py <<: *job-windows - name: i686-msvc-2 env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make ci-msvc-ps1-set2 + SCRIPT: make ci-msvc-ps1 <<: *job-windows # x86_64-msvc-ext is split into multiple jobs to run tests in parallel. -- cgit 1.4.1-3-g733a5 From 2e69bd2ce9b9037b22e46545495f32421c06d153 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 19 Jan 2025 14:24:46 +0100 Subject: Add debug assertions to compiler profile Working on the compiler without debug assertions is not a very productive way to work on the compiler. --- src/bootstrap/defaults/config.compiler.toml | 2 ++ src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 2 files changed, 7 insertions(+) (limited to 'src/bootstrap') diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml index a737de3bd08..269b90106e3 100644 --- a/src/bootstrap/defaults/config.compiler.toml +++ b/src/bootstrap/defaults/config.compiler.toml @@ -8,6 +8,8 @@ compiler-docs = true # where adding `debug!()` appears to do nothing. # However, it makes running the compiler slightly slower. debug-logging = true +# Enables debug assertions, which guard from many mistakes when working on the compiler. +debug-assertions = true # Get actually-useful information from backtraces, profiling, etc. with minimal added bytes debuginfo-level = "line-tables-only" # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 85d17c8fa50..a3eb781f147 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -335,4 +335,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Some stamp names in the build artifacts may have changed slightly (e.g., from `llvm-finished-building` to `.llvm-stamp`).", }, + ChangeInfo { + change_id: 135729, + severity: ChangeSeverity::Info, + summary: "Change the compiler profile to default to rust.debug-assertions = true", + }, ]; -- cgit 1.4.1-3-g733a5 From 7d806171d00f53a720e6784a878a98cbef5c3d4a Mon Sep 17 00:00:00 2001 From: Tanvi Pooranmal Meena Date: Mon, 13 Jan 2025 15:38:39 +0530 Subject: Add logic to override profile for non git sources --- src/bootstrap/bootstrap.py | 5 +++++ src/bootstrap/src/core/config/config.rs | 6 ++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 76ee40c6f45..74923af1555 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1268,6 +1268,11 @@ def bootstrap(args): config_toml = "" profile = RustBuild.get_toml_static(config_toml, "profile") + is_non_git_source = not os.path.exists(os.path.join(rust_root, ".git")) + + if profile is None and is_non_git_source: + profile = "dist" + if profile is not None: # Allows creating alias for profile names, allowing # profiles to be renamed while maintaining back compatibility diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1c49063ef5c..a09902a4c38 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2926,10 +2926,8 @@ impl Config { let if_unchanged = || { if self.rust_info.is_from_tarball() { // Git is needed for running "if-unchanged" logic. - println!( - "WARNING: 'if-unchanged' has no effect on tarball sources; ignoring `download-ci-llvm`." - ); - return false; + println!("ERROR: 'if-unchanged' is only compatible with Git managed sources."); + crate::exit!(1); } // Fetching the LLVM submodule is unnecessary for self-tests. -- cgit 1.4.1-3-g733a5 From cedd4cad21298ca8b825ab3c56a84753176dc8e8 Mon Sep 17 00:00:00 2001 From: jyn Date: Fri, 29 Nov 2024 10:28:54 -0500 Subject: ignore linker errors on all platforms --- src/bootstrap/src/core/build_steps/test.rs | 2 ++ src/bootstrap/src/core/builder/cargo.rs | 7 +++++++ 2 files changed, 9 insertions(+) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 9f3e4d9cc89..38e056cbc14 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3577,6 +3577,8 @@ impl Step for CodegenGCC { let mut cargo = build_cargo(); cargo + // cg_gcc's build system ignores RUSTFLAGS. pass some flags through CG_RUSTFLAGS instead. + .env("CG_RUSTFLAGS", "-Alinker-messages") .arg("--") .arg("test") .arg("--use-system-gcc") diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index f9fb19ddb09..031cbb7dcdb 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -269,6 +269,13 @@ impl Cargo { self.rustflags.arg("-Clink-arg=-gz"); } + // Ignore linker warnings for now. These are complicated to fix and don't affect the build. + // FIXME: we should really investigate these... + // cfg(bootstrap) + if compiler.stage != 0 { + self.rustflags.arg("-Alinker-messages"); + } + // Throughout the build Cargo can execute a number of build scripts // compiling C/C++ code and we need to pass compilers, archivers, flags, etc // obtained previously to those build scripts. -- cgit 1.4.1-3-g733a5 From 00381ead1af39db9e5ce24a8da4dda59b714dbf7 Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Thu, 2 Jan 2025 18:02:57 +0100 Subject: Make it possible to build GCC on CI This is the first step to enable download of precompiled GCC --- src/bootstrap/src/core/build_steps/gcc.rs | 54 ++++++++++++++++++++-- .../host-x86_64/dist-x86_64-linux/Dockerfile | 1 + src/ci/docker/scripts/build-zstd.sh | 6 +++ 3 files changed, 57 insertions(+), 4 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 563b715fa64..98b8635132b 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -12,6 +12,8 @@ use std::fs; use std::path::PathBuf; use std::sync::OnceLock; +use build_helper::ci::CiEnv; + use crate::Kind; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; @@ -112,16 +114,60 @@ impl Step for Gcc { return true; } - command(root.join("contrib/download_prerequisites")).current_dir(&root).run(builder); - command(root.join("configure")) + // GCC creates files (e.g. symlinks to the downloaded dependencies) + // in the source directory, which does not work with our CI setup, where we mount + // source directories as read-only on Linux. + // Therefore, as a part of the build in CI, we first copy the whole source directory + // to the build directory, and perform the build from there. + let src_dir = if CiEnv::is_ci() { + let src_dir = builder.gcc_out(target).join("src"); + if src_dir.exists() { + builder.remove_dir(&src_dir); + } + builder.create_dir(&src_dir); + builder.cp_link_r(&root, &src_dir); + src_dir + } else { + root + }; + + command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder); + let mut configure_cmd = command(src_dir.join("configure")); + configure_cmd .current_dir(&out_dir) + // On CI, we compile GCC with Clang. + // The -Wno-everything flag is needed to make GCC compile with Clang 19. + // `-g -O2` are the default flags that are otherwise used by Make. + // FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml. + .env("CXXFLAGS", "-Wno-everything -g -O2") + .env("CFLAGS", "-Wno-everything -g -O2") .arg("--enable-host-shared") .arg("--enable-languages=jit") .arg("--enable-checking=release") .arg("--disable-bootstrap") .arg("--disable-multilib") - .arg(format!("--prefix={}", install_dir.display())) - .run(builder); + .arg(format!("--prefix={}", install_dir.display())); + let cc = builder.build.cc(target).display().to_string(); + let cc = builder + .build + .config + .ccache + .as_ref() + .map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}")); + configure_cmd.env("CC", cc); + + if let Ok(ref cxx) = builder.build.cxx(target) { + let cxx = cxx.display().to_string(); + let cxx = builder + .build + .config + .ccache + .as_ref() + .map_or_else(|| cxx.clone(), |ccache| format!("{ccache} {cxx}")); + configure_cmd.env("CXX", cxx); + } + configure_cmd.run(builder); + command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())).run(builder); command("make").current_dir(&out_dir).arg("install").run(builder); diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index dde6fe7f6d0..3a396230582 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -34,6 +34,7 @@ RUN yum upgrade -y && \ python3 \ unzip \ wget \ + flex \ xz \ zlib-devel.i686 \ zlib-devel.x86_64 \ diff --git a/src/ci/docker/scripts/build-zstd.sh b/src/ci/docker/scripts/build-zstd.sh index a3d37ccc311..cffa7151e38 100755 --- a/src/ci/docker/scripts/build-zstd.sh +++ b/src/ci/docker/scripts/build-zstd.sh @@ -25,5 +25,11 @@ cd zstd-$ZSTD CFLAGS=-fPIC hide_output make -j$(nproc) VERBOSE=1 hide_output make install +# It doesn't seem to be possible to move destination directory +# of the `make install` above. We thus copy the built artifacts +# manually to our custom rustroot, so that it can be found through +# LD_LIBRARY_PATH. +cp /usr/local/lib/libzstd* /rustroot/lib64 + cd .. rm -rf zstd-$ZSTD -- cgit 1.4.1-3-g733a5 From 5619398f40d161da267bc9634d2c9c8ae7b47742 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 14 Jan 2025 17:40:15 +0300 Subject: bump bootsrap windows to 0.57 --- src/bootstrap/Cargo.lock | 25 +++---------------------- src/bootstrap/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 23 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index c46aae2ded1..d2f3c7f36ca 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -62,7 +62,7 @@ dependencies = [ "tracing-subscriber", "tracing-tree", "walkdir", - "windows 0.52.0", + "windows", "xz2", ] @@ -663,7 +663,7 @@ dependencies = [ "libc", "memchr", "ntapi", - "windows 0.57.0", + "windows", ] [[package]] @@ -843,32 +843,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core 0.52.0", - "windows-targets", -] - [[package]] name = "windows" version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core 0.57.0", - "windows-targets", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ + "windows-core", "windows-targets", ] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 71c56c4e85e..d7afcc7f27d 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -74,7 +74,7 @@ tracing-tree = { version = "0.4.0", optional = true } version = "1.0.0" [target.'cfg(windows)'.dependencies.windows] -version = "0.52" +version = "0.57" features = [ "Win32_Foundation", "Win32_Security", -- cgit 1.4.1-3-g733a5 From f0dfda124d436f01c57f70f26efc22d35ef3a9fa Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 22 Jan 2025 16:50:15 +0300 Subject: fix outdated file path ref in llvm This was added years ago and is outdated today. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/llvm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index cf55fff4078..3cf25373b89 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1338,7 +1338,7 @@ impl Step for CrtBeginEnd { .file(crtbegin_src) .file(crtend_src); - // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt + // Those flags are defined in src/llvm-project/compiler-rt/lib/builtins/CMakeLists.txt // Currently only consumer of those objects is musl, which use .init_array/.fini_array // instead of .ctors/.dtors cfg.flag("-std=c11") -- cgit 1.4.1-3-g733a5 From c568da9f161d1180fddbdfdcc1d1864ffa7619aa Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 22 Jan 2025 19:36:17 +0300 Subject: make bootstrap self test to use bootstrap cargo Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/test.rs | 39 +++++++++++++++++++----------- src/bootstrap/src/core/config/tests.rs | 2 +- 2 files changed, 26 insertions(+), 15 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 9f3e4d9cc89..5f9279624b3 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3113,23 +3113,34 @@ impl Step for Bootstrap { // Use `python -m unittest` manually if you want to pass arguments. check_bootstrap.delay_failure().run(builder); - let mut cmd = command(&builder.initial_cargo); - cmd.arg("test") - .current_dir(builder.src.join("src/bootstrap")) - .env("RUSTFLAGS", "--cfg test -Cdebuginfo=2") + let mut cargo = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolBootstrap, + host, + Kind::Test, + "src/bootstrap", + SourceType::InTree, + &[], + ); + + cargo + .rustflag("-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) - .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTDOC", builder.rustdoc(compiler)) - .env("RUSTC", &builder.initial_rustc); - if let Some(flags) = option_env!("RUSTFLAGS") { - // Use the same rustc flags for testing as for "normal" compilation, - // so that Cargo doesn’t recompile the entire dependency graph every time: - // https://github.com/rust-lang/rust/issues/49215 - cmd.env("RUSTFLAGS", flags); - } + .env("RUSTC_BOOTSTRAP", "1"); + // bootstrap tests are racy on directory creation so just run them one at a time. // Since there's not many this shouldn't be a problem. - run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", None, compiler, host, builder); + run_cargo_test( + cargo, + &["--test-threads=1"], + &[], + "bootstrap", + None, + compiler, + host, + builder, + ); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index c5e578ff351..f0a185ee3a7 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -92,7 +92,7 @@ fn detect_src_and_out() { // `{build-dir}/bootstrap/debug/deps/bootstrap-c7ee91d5661e2804` // `{build-dir}` can be anywhere, not just in the rust project directory. let dep = Path::new(args.first().unwrap()); - let expected_out = dep.ancestors().nth(4).unwrap(); + let expected_out = dep.ancestors().nth(5).unwrap(); assert_eq!(&cfg.out, expected_out); } -- cgit 1.4.1-3-g733a5 From 17b2ede40d61da7c699b47b522cb9909950c5dff Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 22 Jan 2025 19:45:52 +0300 Subject: resolve clippy FIXME Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/test.rs | 62 +++++------------------------- src/bootstrap/src/core/builder/cargo.rs | 4 ++ 2 files changed, 14 insertions(+), 52 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 5f9279624b3..285376431b1 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -87,7 +87,7 @@ impl Step for CrateBootstrap { &[], ); let crate_name = path.rsplit_once('/').unwrap().1; - run_cargo_test(cargo, &[], &[], crate_name, crate_name, compiler, bootstrap_host, builder); + run_cargo_test(cargo, &[], &[], crate_name, crate_name, bootstrap_host, builder); } } @@ -143,7 +143,6 @@ You can skip linkcheck with --skip src/tools/linkchecker" &[], "linkchecker", "linkchecker self tests", - compiler, bootstrap_host, builder, ); @@ -397,7 +396,7 @@ impl Step for RustAnalyzer { cargo.env("SKIP_SLOW_TESTS", "1"); cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", compiler, host, builder); + run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", host, builder); } } @@ -445,7 +444,7 @@ impl Step for Rustfmt { cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", compiler, host, builder); + run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", host, builder); } } @@ -713,16 +712,7 @@ impl Step for CompiletestTest { &[], ); cargo.allow_features("test"); - run_cargo_test( - cargo, - &[], - &[], - "compiletest", - "compiletest self test", - compiler, - host, - builder, - ); + run_cargo_test(cargo, &[], &[], "compiletest", "compiletest self test", host, builder); } } @@ -1294,7 +1284,6 @@ impl Step for CrateRunMakeSupport { &[], "run-make-support", "run-make-support self test", - compiler, host, builder, ); @@ -1334,16 +1323,7 @@ impl Step for CrateBuildHelper { &[], ); cargo.allow_features("test"); - run_cargo_test( - cargo, - &[], - &[], - "build_helper", - "build_helper self test", - compiler, - host, - builder, - ); + run_cargo_test(cargo, &[], &[], "build_helper", "build_helper self test", host, builder); } } @@ -2540,17 +2520,16 @@ impl Step for CrateLibrustc { /// Given a `cargo test` subcommand, add the appropriate flags and run it. /// /// Returns whether the test succeeded. -#[allow(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this. fn run_cargo_test<'a>( - cargo: impl Into, + cargo: builder::Cargo, libtest_args: &[&str], crates: &[String], primary_crate: &str, description: impl Into>, - compiler: Compiler, target: TargetSelection, builder: &Builder<'_>, ) -> bool { + let compiler = cargo.compiler(); let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder); let _time = helpers::timeit(builder); @@ -2793,7 +2772,6 @@ impl Step for Crate { &self.crates, &self.crates[0], &*crate_description(&self.crates), - compiler, target, builder, ); @@ -2895,7 +2873,6 @@ impl Step for CrateRustdoc { &["rustdoc:0.0.0".to_string()], "rustdoc", "rustdoc", - compiler, target, builder, ); @@ -2956,7 +2933,6 @@ impl Step for CrateRustdocJsonTypes { &["rustdoc-json-types".to_string()], "rustdoc-json-types", "rustdoc-json-types", - compiler, target, builder, ); @@ -3131,16 +3107,7 @@ impl Step for Bootstrap { // bootstrap tests are racy on directory creation so just run them one at a time. // Since there's not many this shouldn't be a problem. - run_cargo_test( - cargo, - &["--test-threads=1"], - &[], - "bootstrap", - None, - compiler, - host, - builder, - ); + run_cargo_test(cargo, &["--test-threads=1"], &[], "bootstrap", None, host, builder); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -3265,7 +3232,7 @@ impl Step for RustInstaller { bootstrap_host, bootstrap_host, ); - run_cargo_test(cargo, &[], &[], "installer", None, compiler, bootstrap_host, builder); + run_cargo_test(cargo, &[], &[], "installer", None, bootstrap_host, builder); // We currently don't support running the test.sh script outside linux(?) environments. // Eventually this should likely migrate to #[test]s in rust-installer proper rather than a @@ -3650,16 +3617,7 @@ impl Step for TestFloatParse { &[], ); - run_cargo_test( - cargo_test, - &[], - &[], - crate_name, - crate_name, - compiler, - bootstrap_host, - builder, - ); + run_cargo_test(cargo_test, &[], &[], crate_name, crate_name, bootstrap_host, builder); // Run the actual parse tests. let mut cargo_run = tool::prepare_tool_cargo( diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index f9fb19ddb09..6b792108784 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -121,6 +121,10 @@ impl Cargo { cargo } + pub fn compiler(&self) -> Compiler { + self.compiler + } + pub fn into_cmd(self) -> BootstrapCommand { self.into() } -- cgit 1.4.1-3-g733a5 From e3a5314e0af1d802b01f26afaf983f7cba5e6003 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 22 Jan 2025 19:48:44 +0300 Subject: reduce number of `prepare_cargo_test` args Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/test.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 285376431b1..0d3ab6ad97d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -311,7 +311,7 @@ impl Step for Cargo { ); // NOTE: can't use `run_cargo_test` because we need to overwrite `PATH` - let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", compiler, self.host, builder); + let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", self.host, builder); // Don't run cross-compile tests, we may not have cross-compiled libstd libs // available. @@ -564,7 +564,7 @@ impl Step for Miri { // We can NOT use `run_cargo_test` since Miri's integration tests do not use the usual test // harness and therefore do not understand the flags added by `add_flags_and_try_run_test`. - let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host_compiler, host, builder); + let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host, builder); // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", &miri_sysroot); @@ -759,7 +759,7 @@ impl Step for Clippy { cargo.env("HOST_LIBS", host_libs); cargo.add_rustc_lib_path(builder); - let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder); + let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", host, builder); let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); @@ -2530,8 +2530,7 @@ fn run_cargo_test<'a>( builder: &Builder<'_>, ) -> bool { let compiler = cargo.compiler(); - let mut cargo = - prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder); + let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, primary_crate, target, builder); let _time = helpers::timeit(builder); let _group = description.into().and_then(|what| { builder.msg_sysroot_tool(Kind::Test, compiler.stage, what, compiler.host, target) @@ -2552,15 +2551,15 @@ fn run_cargo_test<'a>( /// Given a `cargo test` subcommand, pass it the appropriate test flags given a `builder`. fn prepare_cargo_test( - cargo: impl Into, + cargo: builder::Cargo, libtest_args: &[&str], crates: &[String], primary_crate: &str, - compiler: Compiler, target: TargetSelection, builder: &Builder<'_>, ) -> BootstrapCommand { - let mut cargo = cargo.into(); + let compiler = cargo.compiler(); + let mut cargo: BootstrapCommand = cargo.into(); // Propagate `--bless` if it has not already been set/unset // Any tools that want to use this should bless if `RUSTC_BLESS` is set to -- cgit 1.4.1-3-g733a5 From 84c80151cf496d0c6e6823493fd4a07d242ce311 Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Thu, 28 Nov 2024 14:06:34 +0100 Subject: Add new target for supporting Neutrino QNX 6.1 with `io-socket` network stack on aarch64 Signed-off-by: Florian Bartels --- compiler/rustc_target/src/spec/mod.rs | 1 + .../targets/aarch64_unknown_nto_qnx710_iosock.rs | 27 ++++++++++++++++++++++ library/std/Cargo.toml | 3 ++- .../std/src/sys/pal/unix/process/process_unix.rs | 7 +++--- src/bootstrap/src/core/sanity.rs | 1 + src/doc/rustc/src/platform-support.md | 4 +++- src/doc/rustc/src/platform-support/nto-qnx.md | 15 +++++++++--- tests/assembly/targets/targets-elf.rs | 3 +++ tests/ui/check-cfg/well-known-values.stderr | 2 +- 9 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs (limited to 'src/bootstrap') diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 37564ab38fc..df6d117f376 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1963,6 +1963,7 @@ supported_targets! { ("aarch64-unknown-nto-qnx700", aarch64_unknown_nto_qnx700), ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710), + ("aarch64-unknown-nto-qnx710_iosock", aarch64_unknown_nto_qnx710_iosock), ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710), ("i586-pc-nto-qnx700", i586_pc_nto_qnx700), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs new file mode 100644 index 00000000000..c9ffc0e072c --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710_iosock.rs @@ -0,0 +1,27 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + let mut target = super::aarch64_unknown_nto_qnx710::target(); + target.options.env = "nto71_iosock".into(); + target.options.pre_link_args = + TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ + "-Vgcc_ntoaarch64le_cxx", + get_iosock_param(), + ]); + target +} + +// When using `io-sock` on QNX, we must add a search path for the linker so +// that it prefers the io-sock version. +// The path depends on the host, i.e. we cannot hard-code it here, but have +// to determine it when the compiler runs. +// When using the QNX toolchain, the environment variable QNX_TARGET is always set. +// More information: +// https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html +fn get_iosock_param() -> &'static str { + let target_dir = + std::env::var("QNX_TARGET").unwrap_or_else(|_| "PLEASE_SET_ENV_VAR_QNX_TARGET".into()); + let linker_param = format!("-L{target_dir}/aarch64le/io-sock/lib"); + + linker_param.leak() +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index da58d7c13bd..b91b89b7761 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -139,7 +139,8 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa"))', + 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock"))', + 'cfg(target_env, values("nto71_iosock"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index ec4965c1d71..cc22b3ecbd0 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -20,7 +20,7 @@ use crate::{fmt, mem, sys}; cfg_if::cfg_if! { // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - if #[cfg(any(target_env = "nto70", target_env = "nto71"))] { + if #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] { use crate::thread; use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; use crate::time::Duration; @@ -191,7 +191,8 @@ impl Command { target_os = "watchos", target_os = "tvos", target_env = "nto70", - target_env = "nto71" + target_env = "nto71", + target_env = "nto71_iosock", )))] unsafe fn do_fork(&mut self) -> Result { cvt(libc::fork()) @@ -202,7 +203,7 @@ impl Command { // Documentation says "... or try calling fork() again". This is what we do here. // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - #[cfg(any(target_env = "nto70", target_env = "nto71"))] + #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] unsafe fn do_fork(&mut self) -> Result { use crate::sys::os::errno; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index ed0155622c2..418ebbbfb42 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,6 +34,7 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined + "aarch64-unknown-nto-qnx710_iosock", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index a706926f743..d25eaa49dd5 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -254,12 +254,14 @@ target | std | host | notes [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon [`aarch64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | ARM64 FreeBSD +`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit [`aarch64-unknown-illumos`](platform-support/illumos.md) | ✓ | ✓ | ARM64 illumos `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD -[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | +[`aarch64-unknown-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with new network stack (io-sock) | [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS | +[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | [`aarch64-unknown-nuttx`](platform-support/nuttx.md) | * | | ARM64 with NuttX [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ | | ARM64 Redox OS diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 96e3b58f471..7d6d9ff3223 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -22,11 +22,15 @@ Currently, the following QNX Neutrino versions and compilation targets are suppo | QNX Neutrino Version | Target Architecture | Full support | `no_std` support | |----------------------|---------------------|:------------:|:----------------:| -| 7.1 | AArch64 | ✓ | ✓ | +| 7.1 with io-pkt | AArch64 | ✓ | ✓ | +| 7.1 with io-sock | AArch64 | ✓ | ✓ | | 7.1 | x86_64 | ✓ | ✓ | | 7.0 | AArch64 | ? | ✓ | | 7.0 | x86 | | ✓ | +On QNX 7.0 and 7.1, `io-pkt` is used as network stack by default. QNX 7.1 includes +the optional network stack `io-sock`. + Adding other architectures that are supported by QNX Neutrino is possible. In the table above, 'full support' indicates support for building Rust applications with the full standard library. @@ -107,7 +111,8 @@ There are no further known requirements. For conditional compilation, following QNX Neutrino specific attributes are defined: - `target_os` = `"nto"` -- `target_env` = `"nto71"` (for QNX Neutrino 7.1) +- `target_env` = `"nto71"` (for QNX Neutrino 7.1 with "classic" network stack "io_pkt") +- `target_env` = `"nto71_iosock"` (for QNX Neutrino 7.1 with network stack "io_sock") - `target_env` = `"nto70"` (for QNX Neutrino 7.0) ## Building the target @@ -134,6 +139,10 @@ export build_env=' CFLAGS_aarch64-unknown-nto-qnx710=-Vgcc_ntoaarch64le_cxx CXX_aarch64-unknown-nto-qnx710=qcc AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar + CC_aarch64-unknown-nto-qnx710_iosock=qcc + CFLAGS_aarch64-unknown-nto-qnx710_iosock=-Vgcc_ntoaarch64le_cxx + CXX_aarch64-unknown-nto-qnx710_iosock=qcc + AR_aarch64_unknown_nto_qnx710_iosock=ntoaarch64-ar CC_x86_64-pc-nto-qnx710=qcc CFLAGS_x86_64-pc-nto-qnx710=-Vgcc_ntox86_64_cxx CXX_x86_64-pc-nto-qnx710=qcc @@ -141,7 +150,7 @@ export build_env=' env $build_env \ ./x.py build \ - --target aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \ + --target aarch64-unknown-nto-qnx710_iosock,aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \ rustc library/core library/alloc library/std ``` diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 6bb3389c409..b9d6aaf7929 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -57,6 +57,9 @@ //@ revisions: aarch64_unknown_nto_qnx710 //@ [aarch64_unknown_nto_qnx710] compile-flags: --target aarch64-unknown-nto-qnx710 //@ [aarch64_unknown_nto_qnx710] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nto_qnx710_iosock +//@ [aarch64_unknown_nto_qnx710_iosock] compile-flags: --target aarch64-unknown-nto-qnx710_iosock +//@ [aarch64_unknown_nto_qnx710_iosock] needs-llvm-components: aarch64 //@ revisions: aarch64_unknown_openbsd //@ [aarch64_unknown_openbsd] compile-flags: --target aarch64-unknown-openbsd //@ [aarch64_unknown_openbsd] needs-llvm-components: aarch64 diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 5c1898a0ae3..29bc30815b8 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -156,7 +156,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, and `uclibc` + = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, and `uclibc` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` -- cgit 1.4.1-3-g733a5 From efe53ddd587333a405fcb95d78a72696932275cd Mon Sep 17 00:00:00 2001 From: Florian Bartels Date: Fri, 29 Nov 2024 18:15:05 +0100 Subject: Add support for QNX 7.1 with io-sock on x64 Signed-off-by: Florian Bartels --- compiler/rustc_target/src/spec/mod.rs | 1 + .../spec/targets/x86_64_pc_nto_qnx710_iosock.rs | 27 ++++++++++++++++++++++ library/std/Cargo.toml | 2 +- src/bootstrap/src/core/sanity.rs | 1 + src/doc/rustc/src/platform-support.md | 3 ++- src/doc/rustc/src/platform-support/nto-qnx.md | 11 +++++---- tests/assembly/targets/targets-elf.rs | 3 +++ 7 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs (limited to 'src/bootstrap') diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index df6d117f376..fdfc72b1bea 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1965,6 +1965,7 @@ supported_targets! { ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710), ("aarch64-unknown-nto-qnx710_iosock", aarch64_unknown_nto_qnx710_iosock), ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710), + ("x86_64-pc-nto-qnx710_iosock", x86_64_pc_nto_qnx710_iosock), ("i586-pc-nto-qnx700", i586_pc_nto_qnx700), ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs new file mode 100644 index 00000000000..9a1035fd78e --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx710_iosock.rs @@ -0,0 +1,27 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + let mut target = super::x86_64_pc_nto_qnx710::target(); + target.options.env = "nto71_iosock".into(); + target.options.pre_link_args = + TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ + "-Vgcc_ntox86_64_cxx", + get_iosock_param(), + ]); + target +} + +// When using `io-sock` on QNX, we must add a search path for the linker so +// that it prefers the io-sock version. +// The path depends on the host, i.e. we cannot hard-code it here, but have +// to determine it when the compiler runs. +// When using the QNX toolchain, the environment variable QNX_TARGET is always set. +// More information: +// https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html +fn get_iosock_param() -> &'static str { + let target_dir = + std::env::var("QNX_TARGET").unwrap_or_else(|_| "PLEASE_SET_ENV_VAR_QNX_TARGET".into()); + let linker_param = format!("-L{target_dir}/x86_64/io-sock/lib"); + + linker_param.leak() +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index b91b89b7761..16e7cb5c3a8 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -139,7 +139,7 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock"))', + 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock"))', 'cfg(target_env, values("nto71_iosock"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 418ebbbfb42..87d273abf17 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -35,6 +35,7 @@ pub struct Finder { const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "aarch64-unknown-nto-qnx710_iosock", + "x86_64-pc-nto-qnx710_iosock", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d25eaa49dd5..de950dbfbe0 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -406,7 +406,8 @@ target | std | host | notes [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator -[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS | +[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | +[`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) | [`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ | | 64-bit Unikraft with musl 1.2.3 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 7d6d9ff3223..1bfd97b8f34 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -22,11 +22,12 @@ Currently, the following QNX Neutrino versions and compilation targets are suppo | QNX Neutrino Version | Target Architecture | Full support | `no_std` support | |----------------------|---------------------|:------------:|:----------------:| -| 7.1 with io-pkt | AArch64 | ✓ | ✓ | -| 7.1 with io-sock | AArch64 | ✓ | ✓ | -| 7.1 | x86_64 | ✓ | ✓ | -| 7.0 | AArch64 | ? | ✓ | -| 7.0 | x86 | | ✓ | +| 7.1 with io-pkt | AArch64 | ✓ | ✓ | +| 7.1 with io-sock | AArch64 | ? | ✓ | +| 7.1 with io-pkt | x86_64 | ✓ | ✓ | +| 7.1 with io-sock | x86_64 | ? | ✓ | +| 7.0 | AArch64 | ? | ✓ | +| 7.0 | x86 | | ✓ | On QNX 7.0 and 7.1, `io-pkt` is used as network stack by default. QNX 7.1 includes the optional network stack `io-sock`. diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index b9d6aaf7929..9f2711880c7 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -567,6 +567,9 @@ //@ revisions: x86_64_pc_nto_qnx710 //@ [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710 //@ [x86_64_pc_nto_qnx710] needs-llvm-components: x86 +//@ revisions: x86_64_pc_nto_qnx710_iosock +//@ [x86_64_pc_nto_qnx710_iosock] compile-flags: --target x86_64-pc-nto-qnx710_iosock +//@ [x86_64_pc_nto_qnx710_iosock] needs-llvm-components: x86 //@ revisions: x86_64_pc_solaris //@ [x86_64_pc_solaris] compile-flags: --target x86_64-pc-solaris //@ [x86_64_pc_solaris] needs-llvm-components: x86 -- cgit 1.4.1-3-g733a5 From 3f045c9d2e186402c135caf6cbc7fc8a41a684b6 Mon Sep 17 00:00:00 2001 From: AkhilTThomas Date: Fri, 6 Dec 2024 11:38:25 +0100 Subject: add nto80 x86-64 and aarch64 target Signed-off-by: Florian Bartels --- compiler/rustc_target/src/spec/mod.rs | 2 ++ .../src/spec/targets/aarch64_unknown_nto_qnx800.rs | 11 +++++++++++ .../rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs | 11 +++++++++++ library/std/Cargo.toml | 4 ++-- library/std/src/sys/pal/unix/process/process_unix.rs | 14 +++----------- src/bootstrap/src/core/sanity.rs | 2 ++ src/doc/rustc/src/platform-support/nto-qnx.md | 1 + tests/assembly/targets/targets-elf.rs | 6 ++++++ tests/ui/check-cfg/well-known-values.stderr | 2 +- 9 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs (limited to 'src/bootstrap') diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index fdfc72b1bea..bcd2aff54bb 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1964,8 +1964,10 @@ supported_targets! { ("aarch64-unknown-nto-qnx700", aarch64_unknown_nto_qnx700), ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710), ("aarch64-unknown-nto-qnx710_iosock", aarch64_unknown_nto_qnx710_iosock), + ("aarch64-unknown-nto-qnx800", aarch64_unknown_nto_qnx800), ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710), ("x86_64-pc-nto-qnx710_iosock", x86_64_pc_nto_qnx710_iosock), + ("x86_64-pc-nto-qnx800", x86_64_pc_nto_qnx800), ("i586-pc-nto-qnx700", i586_pc_nto_qnx700), ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs new file mode 100644 index 00000000000..5b820681efe --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx800.rs @@ -0,0 +1,11 @@ +use crate::spec::Target; +use crate::spec::base::nto_qnx; + +pub(crate) fn target() -> Target { + let mut target = nto_qnx::aarch64(); + target.metadata.description = Some("ARM64 QNX Neutrino 8.0 RTOS".into()); + target.options.pre_link_args = + nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::Aarch64); + target.options.env = "nto80".into(); + target +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs new file mode 100644 index 00000000000..d91a94a2ba5 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_nto_qnx800.rs @@ -0,0 +1,11 @@ +use crate::spec::Target; +use crate::spec::base::nto_qnx; + +pub(crate) fn target() -> Target { + let mut target = nto_qnx::x86_64(); + target.metadata.description = Some("x86 64-bit QNX Neutrino 8.0 RTOS".into()); + target.options.pre_link_args = + nto_qnx::pre_link_args(nto_qnx::ApiVariant::Default, nto_qnx::Arch::X86_64); + target.options.env = "nto80".into(); + target +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 16e7cb5c3a8..9eab75b0696 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -139,8 +139,8 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock"))', - 'cfg(target_env, values("nto71_iosock"))', + 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock", "x86_64-pc-nto-qnx800","aarch64-unknown-nto-qnx800"))', + 'cfg(target_env, values("nto71_iosock", "nto80"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index cc22b3ecbd0..2bff192a5bd 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -19,8 +19,7 @@ use crate::sys::process::process_common::*; use crate::{fmt, mem, sys}; cfg_if::cfg_if! { - // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - if #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] { + if #[cfg(target_os = "nto")] { use crate::thread; use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; use crate::time::Duration; @@ -187,13 +186,7 @@ impl Command { // Attempts to fork the process. If successful, returns Ok((0, -1)) // in the child, and Ok((child_pid, -1)) in the parent. - #[cfg(not(any( - target_os = "watchos", - target_os = "tvos", - target_env = "nto70", - target_env = "nto71", - target_env = "nto71_iosock", - )))] + #[cfg(not(any(target_os = "watchos", target_os = "tvos", target_os = "nto")))] unsafe fn do_fork(&mut self) -> Result { cvt(libc::fork()) } @@ -202,8 +195,7 @@ impl Command { // or closed a file descriptor while the fork() was occurring". // Documentation says "... or try calling fork() again". This is what we do here. // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html - // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0 - #[cfg(any(target_env = "nto70", target_env = "nto71", target_env = "nto71_iosock"))] + #[cfg(target_os = "nto")] unsafe fn do_fork(&mut self) -> Result { use crate::sys::os::errno; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 87d273abf17..6c8cda18548 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -36,6 +36,8 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock", + "x86_64-pc-nto-qnx800", + "aarch64-unknown-nto-qnx800", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 75f8cbad959..4c4bd0494fe 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -115,6 +115,7 @@ For conditional compilation, following QNX Neutrino specific attributes are defi - `target_env` = `"nto71"` (for QNX Neutrino 7.1 with "classic" network stack "io_pkt") - `target_env` = `"nto71_iosock"` (for QNX Neutrino 7.1 with network stack "io_sock") - `target_env` = `"nto70"` (for QNX Neutrino 7.0) +- `target_env` = `"nto80"` (for QNX Neutrino 8.0) ## Building the target diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 9f2711880c7..0ff886653a4 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -60,6 +60,9 @@ //@ revisions: aarch64_unknown_nto_qnx710_iosock //@ [aarch64_unknown_nto_qnx710_iosock] compile-flags: --target aarch64-unknown-nto-qnx710_iosock //@ [aarch64_unknown_nto_qnx710_iosock] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nto_qnx800 +//@ [aarch64_unknown_nto_qnx800] compile-flags: --target aarch64-unknown-nto-qnx800 +//@ [aarch64_unknown_nto_qnx800] needs-llvm-components: aarch64 //@ revisions: aarch64_unknown_openbsd //@ [aarch64_unknown_openbsd] compile-flags: --target aarch64-unknown-openbsd //@ [aarch64_unknown_openbsd] needs-llvm-components: aarch64 @@ -570,6 +573,9 @@ //@ revisions: x86_64_pc_nto_qnx710_iosock //@ [x86_64_pc_nto_qnx710_iosock] compile-flags: --target x86_64-pc-nto-qnx710_iosock //@ [x86_64_pc_nto_qnx710_iosock] needs-llvm-components: x86 +//@ revisions: x86_64_pc_nto_qnx800 +//@ [x86_64_pc_nto_qnx800] compile-flags: --target x86_64-pc-nto-qnx800 +//@ [x86_64_pc_nto_qnx800] needs-llvm-components: x86 //@ revisions: x86_64_pc_solaris //@ [x86_64_pc_solaris] compile-flags: --target x86_64-pc-solaris //@ [x86_64_pc_solaris] needs-llvm-components: x86 diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 29bc30815b8..8ac3cb7ac3c 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -156,7 +156,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, and `uclibc` + = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `nto80`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, and `uclibc` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` -- cgit 1.4.1-3-g733a5 From 7407c1268334a01142d1770dd5080ffeaa8eaa1a Mon Sep 17 00:00:00 2001 From: jyn Date: Mon, 20 Jan 2025 16:44:24 -0500 Subject: Ignore linker warnings on macOS for ui-fulldeps ld is showing things like this: ``` ld: ignoring duplicate libraries: '-lm' ``` I don't have time or a macbook that lets me investigate these. Just silence them for now. --- src/bootstrap/src/core/build_steps/test.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 38e056cbc14..95fbf76b79b 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1862,12 +1862,19 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let mut hostflags = flags.clone(); hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No)); - for flag in hostflags { - cmd.arg("--host-rustcflags").arg(flag); - } let mut targetflags = flags; targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); + + // FIXME: on macOS, we get linker warnings about duplicate `-lm` flags. We should investigate why this happens. + if suite == "ui-fulldeps" && target.ends_with("darwin") { + hostflags.push("-Alinker_messages".into()); + targetflags.push("-Alinker_messages".into()); + } + + for flag in hostflags { + cmd.arg("--host-rustcflags").arg(flag); + } for flag in targetflags { cmd.arg("--target-rustcflags").arg(flag); } -- cgit 1.4.1-3-g733a5 From 571f3ed0c49353a6ceec040bb406a4b364b3766f Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 24 Jan 2025 16:56:00 +0000 Subject: bootstrap: Handle bootstrap lockfile race condition better --- src/bootstrap/src/bin/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index b6552774195..8ebd6b8aa54 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -57,7 +57,9 @@ fn main() { } err => { drop(err); - if let Ok(pid) = pid { + // #135972: We can reach this point when the lock has been taken, + // but the locker has not yet written its PID to the file + if let Some(pid) = pid.ok().filter(|pid| !pid.is_empty()) { println!("WARNING: build directory locked by process {pid}, waiting for lock"); } else { println!("WARNING: build directory locked, waiting for lock"); -- cgit 1.4.1-3-g733a5 From ab7793d4d4d35551480cb2b6823903974316a9fa Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 24 Jan 2025 22:05:30 +0000 Subject: Don't move ownership of job object --- src/bootstrap/bootstrap.py | 3 --- src/bootstrap/src/utils/job.rs | 51 ++++-------------------------------------- 2 files changed, 4 insertions(+), 50 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 74923af1555..01a9792f1b3 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1310,9 +1310,6 @@ def bootstrap(args): args = [build.bootstrap_binary()] args.extend(sys.argv[1:]) env = os.environ.copy() - # The Python process ID is used when creating a Windows job object - # (see src\bootstrap\src\utils\job.rs) - env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) env["BOOTSTRAP_PYTHON"] = sys.executable run(args, env=env, verbose=build.verbose, is_bootstrap=True) diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs index fb69d331d27..10efed130d6 100644 --- a/src/bootstrap/src/utils/job.rs +++ b/src/bootstrap/src/utils/job.rs @@ -42,9 +42,9 @@ pub unsafe fn setup(build: &mut crate::Build) { #[cfg(windows)] mod for_windows { use std::ffi::c_void; - use std::{env, io, mem}; + use std::{io, mem}; - use windows::Win32::Foundation::{CloseHandle, DUPLICATE_SAME_ACCESS, DuplicateHandle, HANDLE}; + use windows::Win32::Foundation::CloseHandle; use windows::Win32::System::Diagnostics::Debug::{ SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE, }; @@ -53,9 +53,7 @@ mod for_windows { JOB_OBJECT_LIMIT_PRIORITY_CLASS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, JobObjectExtendedLimitInformation, SetInformationJobObject, }; - use windows::Win32::System::Threading::{ - BELOW_NORMAL_PRIORITY_CLASS, GetCurrentProcess, OpenProcess, PROCESS_DUP_HANDLE, - }; + use windows::Win32::System::Threading::{BELOW_NORMAL_PRIORITY_CLASS, GetCurrentProcess}; use windows::core::PCWSTR; use crate::Build; @@ -95,49 +93,8 @@ mod for_windows { return; } - // If we've got a parent process (e.g., the python script that called us) - // then move ownership of this job object up to them. That way if the python - // script is killed (e.g., via ctrl-c) then we'll all be torn down. - // - // If we don't have a parent (e.g., this was run directly) then we - // intentionally leak the job object handle. When our process exits + // Note: we intentionally leak the job object handle. When our process exits // (normally or abnormally) it will close the handle implicitly, causing all // processes in the job to be cleaned up. - let pid = match env::var("BOOTSTRAP_PARENT_ID") { - Ok(s) => s, - Err(..) => return, - }; - - let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() { - Some(parent) => parent, - _ => { - // If we get a null parent pointer here, it is possible that either - // we have an invalid pid or the parent process has been closed. - // Since the first case rarely happens - // (only when wrongly setting the environmental variable), - // it might be better to improve the experience of the second case - // when users have interrupted the parent process and we haven't finish - // duplicating the handle yet. - return; - } - }; - - let mut parent_handle = HANDLE::default(); - // If this fails, well at least we tried! An example of DuplicateHandle - // failing in the past has been when the wrong python2 package spawned this - // build system (e.g., the `python2` package in MSYS instead of - // `mingw-w64-x86_64-python2`). Not sure why it failed, but the "failure - // mode" here is that we only clean everything up when the build system - // dies, not when the python parent does, so not too bad. - let _ = DuplicateHandle( - GetCurrentProcess(), - job, - parent, - &mut parent_handle, - 0, - false, - DUPLICATE_SAME_ACCESS, - ); - CloseHandle(parent).ok(); } } -- cgit 1.4.1-3-g733a5 From b6a384194204f34b70fe738e809848ee274b9681 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 4 Dec 2024 13:07:14 +0000 Subject: Put all coretests in a separate crate --- library/Cargo.lock | 4 + library/Cargo.toml | 1 + library/core/Cargo.toml | 13 - library/core/benches/any.rs | 13 - library/core/benches/array.rs | 18 - library/core/benches/ascii.rs | 381 --- library/core/benches/ascii/is_ascii.rs | 123 - library/core/benches/char/methods.rs | 89 - library/core/benches/char/mod.rs | 1 - library/core/benches/fmt.rs | 165 -- library/core/benches/hash/mod.rs | 1 - library/core/benches/hash/sip.rs | 124 - library/core/benches/iter.rs | 548 ---- library/core/benches/lib.rs | 35 - library/core/benches/net/addr_parser.rs | 78 - library/core/benches/net/mod.rs | 1 - library/core/benches/num/dec2flt/mod.rs | 57 - library/core/benches/num/flt2dec/mod.rs | 36 - .../core/benches/num/flt2dec/strategy/dragon.rs | 76 - library/core/benches/num/flt2dec/strategy/grisu.rs | 110 - library/core/benches/num/int_log/mod.rs | 125 - library/core/benches/num/int_pow/mod.rs | 99 - library/core/benches/num/int_sqrt/mod.rs | 62 - library/core/benches/num/mod.rs | 111 - library/core/benches/ops.rs | 20 - library/core/benches/pattern.rs | 41 - library/core/benches/slice.rs | 173 -- library/core/benches/str.rs | 13 - library/core/benches/str/char_count.rs | 108 - library/core/benches/str/corpora.rs | 88 - library/core/benches/str/debug.rs | 80 - library/core/benches/str/iter.rs | 18 - library/core/benches/tuple.rs | 22 - library/core/tests/alloc.rs | 75 - library/core/tests/any.rs | 149 -- library/core/tests/array.rs | 719 ------ library/core/tests/ascii.rs | 507 ---- library/core/tests/ascii_char.rs | 28 - library/core/tests/asserting.rs | 37 - library/core/tests/async_iter/mod.rs | 16 - library/core/tests/atomic.rs | 318 --- library/core/tests/bool.rs | 107 - library/core/tests/bstr.rs | 54 - library/core/tests/cell.rs | 479 ---- library/core/tests/char.rs | 420 --- library/core/tests/clone.rs | 123 - library/core/tests/cmp.rs | 250 -- library/core/tests/const_ptr.rs | 101 - library/core/tests/convert.rs | 18 - library/core/tests/error.rs | 66 - library/core/tests/ffi.rs | 1 - library/core/tests/ffi/cstr.rs | 15 - library/core/tests/fmt/builders.rs | 1044 -------- library/core/tests/fmt/float.rs | 175 -- library/core/tests/fmt/mod.rs | 82 - library/core/tests/fmt/num.rs | 240 -- library/core/tests/future.rs | 127 - library/core/tests/hash/mod.rs | 167 -- library/core/tests/hash/sip.rs | 323 --- library/core/tests/intrinsics.rs | 195 -- library/core/tests/io/borrowed_buf.rs | 167 -- library/core/tests/io/mod.rs | 1 - library/core/tests/iter/adapters/array_chunks.rs | 179 -- library/core/tests/iter/adapters/by_ref_sized.rs | 20 - library/core/tests/iter/adapters/chain.rs | 293 --- library/core/tests/iter/adapters/cloned.rs | 52 - library/core/tests/iter/adapters/copied.rs | 18 - library/core/tests/iter/adapters/cycle.rs | 31 - library/core/tests/iter/adapters/enumerate.rs | 122 - library/core/tests/iter/adapters/filter.rs | 65 - library/core/tests/iter/adapters/filter_map.rs | 50 - library/core/tests/iter/adapters/flat_map.rs | 74 - library/core/tests/iter/adapters/flatten.rs | 281 -- library/core/tests/iter/adapters/fuse.rs | 75 - library/core/tests/iter/adapters/inspect.rs | 38 - library/core/tests/iter/adapters/intersperse.rs | 154 -- library/core/tests/iter/adapters/map.rs | 27 - library/core/tests/iter/adapters/map_windows.rs | 287 --- library/core/tests/iter/adapters/mod.rs | 210 -- library/core/tests/iter/adapters/peekable.rs | 273 -- library/core/tests/iter/adapters/scan.rs | 20 - library/core/tests/iter/adapters/skip.rs | 238 -- library/core/tests/iter/adapters/skip_while.rs | 50 - library/core/tests/iter/adapters/step_by.rs | 301 --- library/core/tests/iter/adapters/take.rs | 262 -- library/core/tests/iter/adapters/take_while.rs | 29 - library/core/tests/iter/adapters/zip.rs | 319 --- library/core/tests/iter/mod.rs | 101 - library/core/tests/iter/range.rs | 504 ---- library/core/tests/iter/sources.rs | 182 -- library/core/tests/iter/traits/accum.rs | 66 - library/core/tests/iter/traits/double_ended.rs | 91 - library/core/tests/iter/traits/iterator.rs | 651 ----- library/core/tests/iter/traits/mod.rs | 4 - library/core/tests/iter/traits/step.rs | 100 - library/core/tests/lazy.rs | 167 -- library/core/tests/lib.rs | 194 -- library/core/tests/macros.rs | 206 -- library/core/tests/macros_bootstrap.rs | 193 -- library/core/tests/manually_drop.rs | 29 - library/core/tests/mem.rs | 797 ------ library/core/tests/net/ip_addr.rs | 1092 -------- library/core/tests/net/mod.rs | 13 - library/core/tests/net/parser.rs | 150 -- library/core/tests/net/socket_addr.rs | 244 -- library/core/tests/nonzero.rs | 367 --- library/core/tests/num/bignum.rs | 276 -- library/core/tests/num/const_from.rs | 27 - library/core/tests/num/dec2flt/float.rs | 33 - library/core/tests/num/dec2flt/lemire.rs | 53 - library/core/tests/num/dec2flt/mod.rs | 129 - library/core/tests/num/dec2flt/parse.rs | 177 -- library/core/tests/num/float_iter_sum_identity.rs | 27 - library/core/tests/num/flt2dec/estimator.rs | 62 - library/core/tests/num/flt2dec/mod.rs | 1168 --------- library/core/tests/num/flt2dec/random.rs | 191 -- library/core/tests/num/flt2dec/strategy/dragon.rs | 64 - library/core/tests/num/flt2dec/strategy/grisu.rs | 73 - library/core/tests/num/i128.rs | 1 - library/core/tests/num/i16.rs | 1 - library/core/tests/num/i32.rs | 30 - library/core/tests/num/i64.rs | 1 - library/core/tests/num/i8.rs | 1 - library/core/tests/num/ieee754.rs | 158 -- library/core/tests/num/int_log.rs | 188 -- library/core/tests/num/int_macros.rs | 482 ---- library/core/tests/num/int_sqrt.rs | 248 -- library/core/tests/num/midpoint.rs | 54 - library/core/tests/num/mod.rs | 952 ------- library/core/tests/num/nan.rs | 7 - library/core/tests/num/ops.rs | 238 -- library/core/tests/num/u128.rs | 1 - library/core/tests/num/u16.rs | 1 - library/core/tests/num/u32.rs | 1 - library/core/tests/num/u64.rs | 1 - library/core/tests/num/u8.rs | 1 - library/core/tests/num/uint_macros.rs | 321 --- library/core/tests/num/wrapping.rs | 316 --- library/core/tests/ops.rs | 242 -- library/core/tests/ops/control_flow.rs | 18 - library/core/tests/ops/from_residual.rs | 26 - library/core/tests/option.rs | 586 ----- library/core/tests/panic.rs | 1 - library/core/tests/panic/location.rs | 31 - library/core/tests/pattern.rs | 503 ---- library/core/tests/pin.rs | 81 - library/core/tests/pin_macro.rs | 32 - library/core/tests/ptr.rs | 994 -------- library/core/tests/result.rs | 423 --- library/core/tests/simd.rs | 13 - library/core/tests/slice.rs | 2688 -------------------- library/core/tests/str.rs | 1 - library/core/tests/str_lossy.rs | 83 - library/core/tests/task.rs | 25 - library/core/tests/time.rs | 564 ---- library/core/tests/tuple.rs | 61 - library/core/tests/unicode.rs | 5 - library/core/tests/waker.rs | 51 - library/coretests/Cargo.toml | 27 + library/coretests/benches/any.rs | 13 + library/coretests/benches/array.rs | 18 + library/coretests/benches/ascii.rs | 381 +++ library/coretests/benches/ascii/is_ascii.rs | 123 + library/coretests/benches/char/methods.rs | 89 + library/coretests/benches/char/mod.rs | 1 + library/coretests/benches/fmt.rs | 165 ++ library/coretests/benches/hash/mod.rs | 1 + library/coretests/benches/hash/sip.rs | 124 + library/coretests/benches/iter.rs | 548 ++++ library/coretests/benches/lib.rs | 35 + library/coretests/benches/net/addr_parser.rs | 78 + library/coretests/benches/net/mod.rs | 1 + library/coretests/benches/num/dec2flt/mod.rs | 57 + library/coretests/benches/num/flt2dec/mod.rs | 36 + .../benches/num/flt2dec/strategy/dragon.rs | 76 + .../benches/num/flt2dec/strategy/grisu.rs | 110 + library/coretests/benches/num/int_log/mod.rs | 125 + library/coretests/benches/num/int_pow/mod.rs | 99 + library/coretests/benches/num/int_sqrt/mod.rs | 62 + library/coretests/benches/num/mod.rs | 111 + library/coretests/benches/ops.rs | 20 + library/coretests/benches/pattern.rs | 41 + library/coretests/benches/slice.rs | 173 ++ library/coretests/benches/str.rs | 13 + library/coretests/benches/str/char_count.rs | 108 + library/coretests/benches/str/corpora.rs | 88 + library/coretests/benches/str/debug.rs | 80 + library/coretests/benches/str/iter.rs | 18 + library/coretests/benches/tuple.rs | 22 + library/coretests/lib.rs | 1 + library/coretests/tests/alloc.rs | 75 + library/coretests/tests/any.rs | 149 ++ library/coretests/tests/array.rs | 719 ++++++ library/coretests/tests/ascii.rs | 507 ++++ library/coretests/tests/ascii_char.rs | 28 + library/coretests/tests/asserting.rs | 37 + library/coretests/tests/async_iter/mod.rs | 16 + library/coretests/tests/atomic.rs | 318 +++ library/coretests/tests/bool.rs | 107 + library/coretests/tests/bstr.rs | 54 + library/coretests/tests/cell.rs | 479 ++++ library/coretests/tests/char.rs | 420 +++ library/coretests/tests/clone.rs | 123 + library/coretests/tests/cmp.rs | 250 ++ library/coretests/tests/const_ptr.rs | 101 + library/coretests/tests/convert.rs | 18 + library/coretests/tests/error.rs | 66 + library/coretests/tests/ffi.rs | 1 + library/coretests/tests/ffi/cstr.rs | 15 + library/coretests/tests/fmt/builders.rs | 1044 ++++++++ library/coretests/tests/fmt/float.rs | 175 ++ library/coretests/tests/fmt/mod.rs | 82 + library/coretests/tests/fmt/num.rs | 240 ++ library/coretests/tests/future.rs | 127 + library/coretests/tests/hash/mod.rs | 167 ++ library/coretests/tests/hash/sip.rs | 323 +++ library/coretests/tests/intrinsics.rs | 195 ++ library/coretests/tests/io/borrowed_buf.rs | 167 ++ library/coretests/tests/io/mod.rs | 1 + .../coretests/tests/iter/adapters/array_chunks.rs | 179 ++ .../coretests/tests/iter/adapters/by_ref_sized.rs | 20 + library/coretests/tests/iter/adapters/chain.rs | 293 +++ library/coretests/tests/iter/adapters/cloned.rs | 52 + library/coretests/tests/iter/adapters/copied.rs | 18 + library/coretests/tests/iter/adapters/cycle.rs | 31 + library/coretests/tests/iter/adapters/enumerate.rs | 122 + library/coretests/tests/iter/adapters/filter.rs | 65 + .../coretests/tests/iter/adapters/filter_map.rs | 50 + library/coretests/tests/iter/adapters/flat_map.rs | 74 + library/coretests/tests/iter/adapters/flatten.rs | 281 ++ library/coretests/tests/iter/adapters/fuse.rs | 75 + library/coretests/tests/iter/adapters/inspect.rs | 38 + .../coretests/tests/iter/adapters/intersperse.rs | 154 ++ library/coretests/tests/iter/adapters/map.rs | 27 + .../coretests/tests/iter/adapters/map_windows.rs | 287 +++ library/coretests/tests/iter/adapters/mod.rs | 210 ++ library/coretests/tests/iter/adapters/peekable.rs | 273 ++ library/coretests/tests/iter/adapters/scan.rs | 20 + library/coretests/tests/iter/adapters/skip.rs | 238 ++ .../coretests/tests/iter/adapters/skip_while.rs | 50 + library/coretests/tests/iter/adapters/step_by.rs | 301 +++ library/coretests/tests/iter/adapters/take.rs | 262 ++ .../coretests/tests/iter/adapters/take_while.rs | 29 + library/coretests/tests/iter/adapters/zip.rs | 319 +++ library/coretests/tests/iter/mod.rs | 101 + library/coretests/tests/iter/range.rs | 504 ++++ library/coretests/tests/iter/sources.rs | 182 ++ library/coretests/tests/iter/traits/accum.rs | 66 + .../coretests/tests/iter/traits/double_ended.rs | 91 + library/coretests/tests/iter/traits/iterator.rs | 651 +++++ library/coretests/tests/iter/traits/mod.rs | 4 + library/coretests/tests/iter/traits/step.rs | 100 + library/coretests/tests/lazy.rs | 167 ++ library/coretests/tests/lib.rs | 194 ++ library/coretests/tests/macros.rs | 206 ++ library/coretests/tests/macros_bootstrap.rs | 193 ++ library/coretests/tests/manually_drop.rs | 29 + library/coretests/tests/mem.rs | 797 ++++++ library/coretests/tests/net/ip_addr.rs | 1092 ++++++++ library/coretests/tests/net/mod.rs | 13 + library/coretests/tests/net/parser.rs | 150 ++ library/coretests/tests/net/socket_addr.rs | 244 ++ library/coretests/tests/nonzero.rs | 367 +++ library/coretests/tests/num/bignum.rs | 276 ++ library/coretests/tests/num/const_from.rs | 27 + library/coretests/tests/num/dec2flt/float.rs | 33 + library/coretests/tests/num/dec2flt/lemire.rs | 53 + library/coretests/tests/num/dec2flt/mod.rs | 129 + library/coretests/tests/num/dec2flt/parse.rs | 177 ++ .../coretests/tests/num/float_iter_sum_identity.rs | 27 + library/coretests/tests/num/flt2dec/estimator.rs | 62 + library/coretests/tests/num/flt2dec/mod.rs | 1168 +++++++++ library/coretests/tests/num/flt2dec/random.rs | 191 ++ .../coretests/tests/num/flt2dec/strategy/dragon.rs | 64 + .../coretests/tests/num/flt2dec/strategy/grisu.rs | 73 + library/coretests/tests/num/i128.rs | 1 + library/coretests/tests/num/i16.rs | 1 + library/coretests/tests/num/i32.rs | 30 + library/coretests/tests/num/i64.rs | 1 + library/coretests/tests/num/i8.rs | 1 + library/coretests/tests/num/ieee754.rs | 158 ++ library/coretests/tests/num/int_log.rs | 188 ++ library/coretests/tests/num/int_macros.rs | 482 ++++ library/coretests/tests/num/int_sqrt.rs | 248 ++ library/coretests/tests/num/midpoint.rs | 54 + library/coretests/tests/num/mod.rs | 952 +++++++ library/coretests/tests/num/nan.rs | 7 + library/coretests/tests/num/ops.rs | 238 ++ library/coretests/tests/num/u128.rs | 1 + library/coretests/tests/num/u16.rs | 1 + library/coretests/tests/num/u32.rs | 1 + library/coretests/tests/num/u64.rs | 1 + library/coretests/tests/num/u8.rs | 1 + library/coretests/tests/num/uint_macros.rs | 321 +++ library/coretests/tests/num/wrapping.rs | 316 +++ library/coretests/tests/ops.rs | 242 ++ library/coretests/tests/ops/control_flow.rs | 18 + library/coretests/tests/ops/from_residual.rs | 26 + library/coretests/tests/option.rs | 586 +++++ library/coretests/tests/panic.rs | 1 + library/coretests/tests/panic/location.rs | 31 + library/coretests/tests/pattern.rs | 503 ++++ library/coretests/tests/pin.rs | 81 + library/coretests/tests/pin_macro.rs | 32 + library/coretests/tests/ptr.rs | 994 ++++++++ library/coretests/tests/result.rs | 423 +++ library/coretests/tests/simd.rs | 13 + library/coretests/tests/slice.rs | 2688 ++++++++++++++++++++ library/coretests/tests/str.rs | 1 + library/coretests/tests/str_lossy.rs | 83 + library/coretests/tests/task.rs | 25 + library/coretests/tests/time.rs | 564 ++++ library/coretests/tests/tuple.rs | 61 + library/coretests/tests/unicode.rs | 5 + library/coretests/tests/waker.rs | 51 + src/bootstrap/mk/Makefile.in | 4 +- src/bootstrap/src/core/build_steps/check.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 2 +- 318 files changed, 29187 insertions(+), 29167 deletions(-) delete mode 100644 library/core/benches/any.rs delete mode 100644 library/core/benches/array.rs delete mode 100644 library/core/benches/ascii.rs delete mode 100644 library/core/benches/ascii/is_ascii.rs delete mode 100644 library/core/benches/char/methods.rs delete mode 100644 library/core/benches/char/mod.rs delete mode 100644 library/core/benches/fmt.rs delete mode 100644 library/core/benches/hash/mod.rs delete mode 100644 library/core/benches/hash/sip.rs delete mode 100644 library/core/benches/iter.rs delete mode 100644 library/core/benches/lib.rs delete mode 100644 library/core/benches/net/addr_parser.rs delete mode 100644 library/core/benches/net/mod.rs delete mode 100644 library/core/benches/num/dec2flt/mod.rs delete mode 100644 library/core/benches/num/flt2dec/mod.rs delete mode 100644 library/core/benches/num/flt2dec/strategy/dragon.rs delete mode 100644 library/core/benches/num/flt2dec/strategy/grisu.rs delete mode 100644 library/core/benches/num/int_log/mod.rs delete mode 100644 library/core/benches/num/int_pow/mod.rs delete mode 100644 library/core/benches/num/int_sqrt/mod.rs delete mode 100644 library/core/benches/num/mod.rs delete mode 100644 library/core/benches/ops.rs delete mode 100644 library/core/benches/pattern.rs delete mode 100644 library/core/benches/slice.rs delete mode 100644 library/core/benches/str.rs delete mode 100644 library/core/benches/str/char_count.rs delete mode 100644 library/core/benches/str/corpora.rs delete mode 100644 library/core/benches/str/debug.rs delete mode 100644 library/core/benches/str/iter.rs delete mode 100644 library/core/benches/tuple.rs delete mode 100644 library/core/tests/alloc.rs delete mode 100644 library/core/tests/any.rs delete mode 100644 library/core/tests/array.rs delete mode 100644 library/core/tests/ascii.rs delete mode 100644 library/core/tests/ascii_char.rs delete mode 100644 library/core/tests/asserting.rs delete mode 100644 library/core/tests/async_iter/mod.rs delete mode 100644 library/core/tests/atomic.rs delete mode 100644 library/core/tests/bool.rs delete mode 100644 library/core/tests/bstr.rs delete mode 100644 library/core/tests/cell.rs delete mode 100644 library/core/tests/char.rs delete mode 100644 library/core/tests/clone.rs delete mode 100644 library/core/tests/cmp.rs delete mode 100644 library/core/tests/const_ptr.rs delete mode 100644 library/core/tests/convert.rs delete mode 100644 library/core/tests/error.rs delete mode 100644 library/core/tests/ffi.rs delete mode 100644 library/core/tests/ffi/cstr.rs delete mode 100644 library/core/tests/fmt/builders.rs delete mode 100644 library/core/tests/fmt/float.rs delete mode 100644 library/core/tests/fmt/mod.rs delete mode 100644 library/core/tests/fmt/num.rs delete mode 100644 library/core/tests/future.rs delete mode 100644 library/core/tests/hash/mod.rs delete mode 100644 library/core/tests/hash/sip.rs delete mode 100644 library/core/tests/intrinsics.rs delete mode 100644 library/core/tests/io/borrowed_buf.rs delete mode 100644 library/core/tests/io/mod.rs delete mode 100644 library/core/tests/iter/adapters/array_chunks.rs delete mode 100644 library/core/tests/iter/adapters/by_ref_sized.rs delete mode 100644 library/core/tests/iter/adapters/chain.rs delete mode 100644 library/core/tests/iter/adapters/cloned.rs delete mode 100644 library/core/tests/iter/adapters/copied.rs delete mode 100644 library/core/tests/iter/adapters/cycle.rs delete mode 100644 library/core/tests/iter/adapters/enumerate.rs delete mode 100644 library/core/tests/iter/adapters/filter.rs delete mode 100644 library/core/tests/iter/adapters/filter_map.rs delete mode 100644 library/core/tests/iter/adapters/flat_map.rs delete mode 100644 library/core/tests/iter/adapters/flatten.rs delete mode 100644 library/core/tests/iter/adapters/fuse.rs delete mode 100644 library/core/tests/iter/adapters/inspect.rs delete mode 100644 library/core/tests/iter/adapters/intersperse.rs delete mode 100644 library/core/tests/iter/adapters/map.rs delete mode 100644 library/core/tests/iter/adapters/map_windows.rs delete mode 100644 library/core/tests/iter/adapters/mod.rs delete mode 100644 library/core/tests/iter/adapters/peekable.rs delete mode 100644 library/core/tests/iter/adapters/scan.rs delete mode 100644 library/core/tests/iter/adapters/skip.rs delete mode 100644 library/core/tests/iter/adapters/skip_while.rs delete mode 100644 library/core/tests/iter/adapters/step_by.rs delete mode 100644 library/core/tests/iter/adapters/take.rs delete mode 100644 library/core/tests/iter/adapters/take_while.rs delete mode 100644 library/core/tests/iter/adapters/zip.rs delete mode 100644 library/core/tests/iter/mod.rs delete mode 100644 library/core/tests/iter/range.rs delete mode 100644 library/core/tests/iter/sources.rs delete mode 100644 library/core/tests/iter/traits/accum.rs delete mode 100644 library/core/tests/iter/traits/double_ended.rs delete mode 100644 library/core/tests/iter/traits/iterator.rs delete mode 100644 library/core/tests/iter/traits/mod.rs delete mode 100644 library/core/tests/iter/traits/step.rs delete mode 100644 library/core/tests/lazy.rs delete mode 100644 library/core/tests/lib.rs delete mode 100644 library/core/tests/macros.rs delete mode 100644 library/core/tests/macros_bootstrap.rs delete mode 100644 library/core/tests/manually_drop.rs delete mode 100644 library/core/tests/mem.rs delete mode 100644 library/core/tests/net/ip_addr.rs delete mode 100644 library/core/tests/net/mod.rs delete mode 100644 library/core/tests/net/parser.rs delete mode 100644 library/core/tests/net/socket_addr.rs delete mode 100644 library/core/tests/nonzero.rs delete mode 100644 library/core/tests/num/bignum.rs delete mode 100644 library/core/tests/num/const_from.rs delete mode 100644 library/core/tests/num/dec2flt/float.rs delete mode 100644 library/core/tests/num/dec2flt/lemire.rs delete mode 100644 library/core/tests/num/dec2flt/mod.rs delete mode 100644 library/core/tests/num/dec2flt/parse.rs delete mode 100644 library/core/tests/num/float_iter_sum_identity.rs delete mode 100644 library/core/tests/num/flt2dec/estimator.rs delete mode 100644 library/core/tests/num/flt2dec/mod.rs delete mode 100644 library/core/tests/num/flt2dec/random.rs delete mode 100644 library/core/tests/num/flt2dec/strategy/dragon.rs delete mode 100644 library/core/tests/num/flt2dec/strategy/grisu.rs delete mode 100644 library/core/tests/num/i128.rs delete mode 100644 library/core/tests/num/i16.rs delete mode 100644 library/core/tests/num/i32.rs delete mode 100644 library/core/tests/num/i64.rs delete mode 100644 library/core/tests/num/i8.rs delete mode 100644 library/core/tests/num/ieee754.rs delete mode 100644 library/core/tests/num/int_log.rs delete mode 100644 library/core/tests/num/int_macros.rs delete mode 100644 library/core/tests/num/int_sqrt.rs delete mode 100644 library/core/tests/num/midpoint.rs delete mode 100644 library/core/tests/num/mod.rs delete mode 100644 library/core/tests/num/nan.rs delete mode 100644 library/core/tests/num/ops.rs delete mode 100644 library/core/tests/num/u128.rs delete mode 100644 library/core/tests/num/u16.rs delete mode 100644 library/core/tests/num/u32.rs delete mode 100644 library/core/tests/num/u64.rs delete mode 100644 library/core/tests/num/u8.rs delete mode 100644 library/core/tests/num/uint_macros.rs delete mode 100644 library/core/tests/num/wrapping.rs delete mode 100644 library/core/tests/ops.rs delete mode 100644 library/core/tests/ops/control_flow.rs delete mode 100644 library/core/tests/ops/from_residual.rs delete mode 100644 library/core/tests/option.rs delete mode 100644 library/core/tests/panic.rs delete mode 100644 library/core/tests/panic/location.rs delete mode 100644 library/core/tests/pattern.rs delete mode 100644 library/core/tests/pin.rs delete mode 100644 library/core/tests/pin_macro.rs delete mode 100644 library/core/tests/ptr.rs delete mode 100644 library/core/tests/result.rs delete mode 100644 library/core/tests/simd.rs delete mode 100644 library/core/tests/slice.rs delete mode 100644 library/core/tests/str.rs delete mode 100644 library/core/tests/str_lossy.rs delete mode 100644 library/core/tests/task.rs delete mode 100644 library/core/tests/time.rs delete mode 100644 library/core/tests/tuple.rs delete mode 100644 library/core/tests/unicode.rs delete mode 100644 library/core/tests/waker.rs create mode 100644 library/coretests/Cargo.toml create mode 100644 library/coretests/benches/any.rs create mode 100644 library/coretests/benches/array.rs create mode 100644 library/coretests/benches/ascii.rs create mode 100644 library/coretests/benches/ascii/is_ascii.rs create mode 100644 library/coretests/benches/char/methods.rs create mode 100644 library/coretests/benches/char/mod.rs create mode 100644 library/coretests/benches/fmt.rs create mode 100644 library/coretests/benches/hash/mod.rs create mode 100644 library/coretests/benches/hash/sip.rs create mode 100644 library/coretests/benches/iter.rs create mode 100644 library/coretests/benches/lib.rs create mode 100644 library/coretests/benches/net/addr_parser.rs create mode 100644 library/coretests/benches/net/mod.rs create mode 100644 library/coretests/benches/num/dec2flt/mod.rs create mode 100644 library/coretests/benches/num/flt2dec/mod.rs create mode 100644 library/coretests/benches/num/flt2dec/strategy/dragon.rs create mode 100644 library/coretests/benches/num/flt2dec/strategy/grisu.rs create mode 100644 library/coretests/benches/num/int_log/mod.rs create mode 100644 library/coretests/benches/num/int_pow/mod.rs create mode 100644 library/coretests/benches/num/int_sqrt/mod.rs create mode 100644 library/coretests/benches/num/mod.rs create mode 100644 library/coretests/benches/ops.rs create mode 100644 library/coretests/benches/pattern.rs create mode 100644 library/coretests/benches/slice.rs create mode 100644 library/coretests/benches/str.rs create mode 100644 library/coretests/benches/str/char_count.rs create mode 100644 library/coretests/benches/str/corpora.rs create mode 100644 library/coretests/benches/str/debug.rs create mode 100644 library/coretests/benches/str/iter.rs create mode 100644 library/coretests/benches/tuple.rs create mode 100644 library/coretests/lib.rs create mode 100644 library/coretests/tests/alloc.rs create mode 100644 library/coretests/tests/any.rs create mode 100644 library/coretests/tests/array.rs create mode 100644 library/coretests/tests/ascii.rs create mode 100644 library/coretests/tests/ascii_char.rs create mode 100644 library/coretests/tests/asserting.rs create mode 100644 library/coretests/tests/async_iter/mod.rs create mode 100644 library/coretests/tests/atomic.rs create mode 100644 library/coretests/tests/bool.rs create mode 100644 library/coretests/tests/bstr.rs create mode 100644 library/coretests/tests/cell.rs create mode 100644 library/coretests/tests/char.rs create mode 100644 library/coretests/tests/clone.rs create mode 100644 library/coretests/tests/cmp.rs create mode 100644 library/coretests/tests/const_ptr.rs create mode 100644 library/coretests/tests/convert.rs create mode 100644 library/coretests/tests/error.rs create mode 100644 library/coretests/tests/ffi.rs create mode 100644 library/coretests/tests/ffi/cstr.rs create mode 100644 library/coretests/tests/fmt/builders.rs create mode 100644 library/coretests/tests/fmt/float.rs create mode 100644 library/coretests/tests/fmt/mod.rs create mode 100644 library/coretests/tests/fmt/num.rs create mode 100644 library/coretests/tests/future.rs create mode 100644 library/coretests/tests/hash/mod.rs create mode 100644 library/coretests/tests/hash/sip.rs create mode 100644 library/coretests/tests/intrinsics.rs create mode 100644 library/coretests/tests/io/borrowed_buf.rs create mode 100644 library/coretests/tests/io/mod.rs create mode 100644 library/coretests/tests/iter/adapters/array_chunks.rs create mode 100644 library/coretests/tests/iter/adapters/by_ref_sized.rs create mode 100644 library/coretests/tests/iter/adapters/chain.rs create mode 100644 library/coretests/tests/iter/adapters/cloned.rs create mode 100644 library/coretests/tests/iter/adapters/copied.rs create mode 100644 library/coretests/tests/iter/adapters/cycle.rs create mode 100644 library/coretests/tests/iter/adapters/enumerate.rs create mode 100644 library/coretests/tests/iter/adapters/filter.rs create mode 100644 library/coretests/tests/iter/adapters/filter_map.rs create mode 100644 library/coretests/tests/iter/adapters/flat_map.rs create mode 100644 library/coretests/tests/iter/adapters/flatten.rs create mode 100644 library/coretests/tests/iter/adapters/fuse.rs create mode 100644 library/coretests/tests/iter/adapters/inspect.rs create mode 100644 library/coretests/tests/iter/adapters/intersperse.rs create mode 100644 library/coretests/tests/iter/adapters/map.rs create mode 100644 library/coretests/tests/iter/adapters/map_windows.rs create mode 100644 library/coretests/tests/iter/adapters/mod.rs create mode 100644 library/coretests/tests/iter/adapters/peekable.rs create mode 100644 library/coretests/tests/iter/adapters/scan.rs create mode 100644 library/coretests/tests/iter/adapters/skip.rs create mode 100644 library/coretests/tests/iter/adapters/skip_while.rs create mode 100644 library/coretests/tests/iter/adapters/step_by.rs create mode 100644 library/coretests/tests/iter/adapters/take.rs create mode 100644 library/coretests/tests/iter/adapters/take_while.rs create mode 100644 library/coretests/tests/iter/adapters/zip.rs create mode 100644 library/coretests/tests/iter/mod.rs create mode 100644 library/coretests/tests/iter/range.rs create mode 100644 library/coretests/tests/iter/sources.rs create mode 100644 library/coretests/tests/iter/traits/accum.rs create mode 100644 library/coretests/tests/iter/traits/double_ended.rs create mode 100644 library/coretests/tests/iter/traits/iterator.rs create mode 100644 library/coretests/tests/iter/traits/mod.rs create mode 100644 library/coretests/tests/iter/traits/step.rs create mode 100644 library/coretests/tests/lazy.rs create mode 100644 library/coretests/tests/lib.rs create mode 100644 library/coretests/tests/macros.rs create mode 100644 library/coretests/tests/macros_bootstrap.rs create mode 100644 library/coretests/tests/manually_drop.rs create mode 100644 library/coretests/tests/mem.rs create mode 100644 library/coretests/tests/net/ip_addr.rs create mode 100644 library/coretests/tests/net/mod.rs create mode 100644 library/coretests/tests/net/parser.rs create mode 100644 library/coretests/tests/net/socket_addr.rs create mode 100644 library/coretests/tests/nonzero.rs create mode 100644 library/coretests/tests/num/bignum.rs create mode 100644 library/coretests/tests/num/const_from.rs create mode 100644 library/coretests/tests/num/dec2flt/float.rs create mode 100644 library/coretests/tests/num/dec2flt/lemire.rs create mode 100644 library/coretests/tests/num/dec2flt/mod.rs create mode 100644 library/coretests/tests/num/dec2flt/parse.rs create mode 100644 library/coretests/tests/num/float_iter_sum_identity.rs create mode 100644 library/coretests/tests/num/flt2dec/estimator.rs create mode 100644 library/coretests/tests/num/flt2dec/mod.rs create mode 100644 library/coretests/tests/num/flt2dec/random.rs create mode 100644 library/coretests/tests/num/flt2dec/strategy/dragon.rs create mode 100644 library/coretests/tests/num/flt2dec/strategy/grisu.rs create mode 100644 library/coretests/tests/num/i128.rs create mode 100644 library/coretests/tests/num/i16.rs create mode 100644 library/coretests/tests/num/i32.rs create mode 100644 library/coretests/tests/num/i64.rs create mode 100644 library/coretests/tests/num/i8.rs create mode 100644 library/coretests/tests/num/ieee754.rs create mode 100644 library/coretests/tests/num/int_log.rs create mode 100644 library/coretests/tests/num/int_macros.rs create mode 100644 library/coretests/tests/num/int_sqrt.rs create mode 100644 library/coretests/tests/num/midpoint.rs create mode 100644 library/coretests/tests/num/mod.rs create mode 100644 library/coretests/tests/num/nan.rs create mode 100644 library/coretests/tests/num/ops.rs create mode 100644 library/coretests/tests/num/u128.rs create mode 100644 library/coretests/tests/num/u16.rs create mode 100644 library/coretests/tests/num/u32.rs create mode 100644 library/coretests/tests/num/u64.rs create mode 100644 library/coretests/tests/num/u8.rs create mode 100644 library/coretests/tests/num/uint_macros.rs create mode 100644 library/coretests/tests/num/wrapping.rs create mode 100644 library/coretests/tests/ops.rs create mode 100644 library/coretests/tests/ops/control_flow.rs create mode 100644 library/coretests/tests/ops/from_residual.rs create mode 100644 library/coretests/tests/option.rs create mode 100644 library/coretests/tests/panic.rs create mode 100644 library/coretests/tests/panic/location.rs create mode 100644 library/coretests/tests/pattern.rs create mode 100644 library/coretests/tests/pin.rs create mode 100644 library/coretests/tests/pin_macro.rs create mode 100644 library/coretests/tests/ptr.rs create mode 100644 library/coretests/tests/result.rs create mode 100644 library/coretests/tests/simd.rs create mode 100644 library/coretests/tests/slice.rs create mode 100644 library/coretests/tests/str.rs create mode 100644 library/coretests/tests/str_lossy.rs create mode 100644 library/coretests/tests/task.rs create mode 100644 library/coretests/tests/time.rs create mode 100644 library/coretests/tests/tuple.rs create mode 100644 library/coretests/tests/unicode.rs create mode 100644 library/coretests/tests/waker.rs (limited to 'src/bootstrap') diff --git a/library/Cargo.lock b/library/Cargo.lock index 7b9081d46a0..30875482dc0 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -72,6 +72,10 @@ dependencies = [ [[package]] name = "core" version = "0.0.0" + +[[package]] +name = "coretests" +version = "0.0.0" dependencies = [ "rand", "rand_xorshift", diff --git a/library/Cargo.toml b/library/Cargo.toml index e59aa518804..1205f7c9ed6 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -3,6 +3,7 @@ resolver = "1" members = [ "std", "sysroot", + "coretests", ] exclude = [ diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 46c55c437cc..b7c6db6c78d 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -15,19 +15,6 @@ edition = "2021" test = false bench = false -[[test]] -name = "coretests" -path = "tests/lib.rs" - -[[bench]] -name = "corebenches" -path = "benches/lib.rs" -test = true - -[dev-dependencies] -rand = { version = "0.8.5", default-features = false } -rand_xorshift = { version = "0.3.0", default-features = false } - [features] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = [] diff --git a/library/core/benches/any.rs b/library/core/benches/any.rs deleted file mode 100644 index 6b150432f87..00000000000 --- a/library/core/benches/any.rs +++ /dev/null @@ -1,13 +0,0 @@ -use core::any::*; - -use test::{Bencher, black_box}; - -#[bench] -fn bench_downcast_ref(b: &mut Bencher) { - b.iter(|| { - let mut x = 0; - let mut y = &mut x as &mut dyn Any; - black_box(&mut y); - black_box(y.downcast_ref::() == Some(&0)); - }); -} diff --git a/library/core/benches/array.rs b/library/core/benches/array.rs deleted file mode 100644 index 751f3235a5f..00000000000 --- a/library/core/benches/array.rs +++ /dev/null @@ -1,18 +0,0 @@ -use test::{Bencher, black_box}; - -macro_rules! map_array { - ($func_name:ident, $start_item: expr, $map_item: expr, $arr_size: expr) => { - #[bench] - fn $func_name(b: &mut Bencher) { - let arr = [$start_item; $arr_size]; - b.iter(|| black_box(arr).map(|_| black_box($map_item))); - } - }; -} - -map_array!(map_8byte_8byte_8, 0u64, 1u64, 80); -map_array!(map_8byte_8byte_64, 0u64, 1u64, 640); -map_array!(map_8byte_8byte_256, 0u64, 1u64, 2560); - -map_array!(map_8byte_256byte_256, 0u64, [0u64; 4], 2560); -map_array!(map_256byte_8byte_256, [0u64; 4], 0u64, 2560); diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs deleted file mode 100644 index 3fe45aa360b..00000000000 --- a/library/core/benches/ascii.rs +++ /dev/null @@ -1,381 +0,0 @@ -mod is_ascii; - -// Lower-case ASCII 'a' is the first byte that has its highest bit set -// after wrap-adding 0x1F: -// -// b'a' + 0x1F == 0x80 == 0b1000_0000 -// b'z' + 0x1F == 0x98 == 0b1001_1000 -// -// Lower-case ASCII 'z' is the last byte that has its highest bit unset -// after wrap-adding 0x05: -// -// b'a' + 0x05 == 0x66 == 0b0110_0110 -// b'z' + 0x05 == 0x7F == 0b0111_1111 -// -// … except for 0xFB to 0xFF, but those are in the range of bytes -// that have the highest bit unset again after adding 0x1F. -// -// So `(byte + 0x1f) & !(byte + 5)` has its highest bit set -// iff `byte` is a lower-case ASCII letter. -// -// Lower-case ASCII letters all have the 0x20 bit set. -// (Two positions right of 0x80, the highest bit.) -// Unsetting that bit produces the same letter, in upper-case. -// -// Therefore: -fn branchless_to_ascii_upper_case(byte: u8) -> u8 { - byte & !((byte.wrapping_add(0x1f) & !byte.wrapping_add(0x05) & 0x80) >> 2) -} - -macro_rules! benches { - ($( fn $name: ident($arg: ident: &mut [u8]) $body: block )+ @iter $( $is_: ident, )+) => { - benches! {@ - $( fn $name($arg: &mut [u8]) $body )+ - $( fn $is_(bytes: &mut [u8]) { bytes.iter().all(u8::$is_) } )+ - } - }; - - (@$( fn $name: ident($arg: ident: &mut [u8]) $body: block )+) => { - benches!(mod short SHORT $($name $arg $body)+); - benches!(mod medium MEDIUM $($name $arg $body)+); - benches!(mod long LONG $($name $arg $body)+); - }; - - (mod $mod_name: ident $input: ident $($name: ident $arg: ident $body: block)+) => { - mod $mod_name { - use super::*; - - $( - #[bench] - fn $name(bencher: &mut Bencher) { - bencher.bytes = $input.len() as u64; - bencher.iter(|| { - let mut vec = $input.as_bytes().to_vec(); - { - let $arg = &mut vec[..]; - black_box($body); - } - vec - }) - } - )+ - } - } -} - -use std::fmt::Write; - -use test::{Bencher, black_box}; - -const ASCII_CASE_MASK: u8 = 0b0010_0000; - -benches! { - fn case00_alloc_only(_bytes: &mut [u8]) {} - - fn case01_black_box_read_each_byte(bytes: &mut [u8]) { - for byte in bytes { - black_box(*byte); - } - } - - fn case02_lookup_table(bytes: &mut [u8]) { - for byte in bytes { - *byte = ASCII_UPPERCASE_MAP[*byte as usize] - } - } - - fn case03_branch_and_subtract(bytes: &mut [u8]) { - for byte in bytes { - *byte = if b'a' <= *byte && *byte <= b'z' { - *byte - b'a' + b'A' - } else { - *byte - } - } - } - - fn case04_branch_and_mask(bytes: &mut [u8]) { - for byte in bytes { - *byte = if b'a' <= *byte && *byte <= b'z' { - *byte & !0x20 - } else { - *byte - } - } - } - - fn case05_branchless(bytes: &mut [u8]) { - for byte in bytes { - *byte = branchless_to_ascii_upper_case(*byte) - } - } - - fn case06_libcore(bytes: &mut [u8]) { - bytes.make_ascii_uppercase() - } - - fn case07_fake_simd_u32(bytes: &mut [u8]) { - // SAFETY: transmuting a sequence of `u8` to `u32` is always fine - let (before, aligned, after) = unsafe { - bytes.align_to_mut::() - }; - for byte in before { - *byte = branchless_to_ascii_upper_case(*byte) - } - for word in aligned { - // FIXME: this is incorrect for some byte values: - // addition within a byte can carry/overflow into the next byte. - // Test case: b"\xFFz " - *word &= !( - ( - word.wrapping_add(0x1f1f1f1f) & - !word.wrapping_add(0x05050505) & - 0x80808080 - ) >> 2 - ) - } - for byte in after { - *byte = branchless_to_ascii_upper_case(*byte) - } - } - - fn case08_fake_simd_u64(bytes: &mut [u8]) { - // SAFETY: transmuting a sequence of `u8` to `u64` is always fine - let (before, aligned, after) = unsafe { - bytes.align_to_mut::() - }; - for byte in before { - *byte = branchless_to_ascii_upper_case(*byte) - } - for word in aligned { - // FIXME: like above, this is incorrect for some byte values. - *word &= !( - ( - word.wrapping_add(0x1f1f1f1f_1f1f1f1f) & - !word.wrapping_add(0x05050505_05050505) & - 0x80808080_80808080 - ) >> 2 - ) - } - for byte in after { - *byte = branchless_to_ascii_upper_case(*byte) - } - } - - fn case09_mask_mult_bool_branchy_lookup_table(bytes: &mut [u8]) { - fn is_ascii_lowercase(b: u8) -> bool { - if b >= 0x80 { return false } - match ASCII_CHARACTER_CLASS[b as usize] { - L | Lx => true, - _ => false, - } - } - for byte in bytes { - *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) - } - } - - fn case10_mask_mult_bool_lookup_table(bytes: &mut [u8]) { - fn is_ascii_lowercase(b: u8) -> bool { - match ASCII_CHARACTER_CLASS[b as usize] { - L | Lx => true, - _ => false - } - } - for byte in bytes { - *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) - } - } - - fn case11_mask_mult_bool_match_range(bytes: &mut [u8]) { - fn is_ascii_lowercase(b: u8) -> bool { - match b { - b'a'..=b'z' => true, - _ => false - } - } - for byte in bytes { - *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) - } - } - - fn case12_mask_shifted_bool_match_range(bytes: &mut [u8]) { - fn is_ascii_lowercase(b: u8) -> bool { - match b { - b'a'..=b'z' => true, - _ => false - } - } - for byte in bytes { - *byte &= !((is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK) - } - } - - fn case13_subtract_shifted_bool_match_range(bytes: &mut [u8]) { - fn is_ascii_lowercase(b: u8) -> bool { - match b { - b'a'..=b'z' => true, - _ => false - } - } - for byte in bytes { - *byte -= (is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK - } - } - - fn case14_subtract_multiplied_bool_match_range(bytes: &mut [u8]) { - fn is_ascii_lowercase(b: u8) -> bool { - match b { - b'a'..=b'z' => true, - _ => false - } - } - for byte in bytes { - *byte -= (b'a' - b'A') * is_ascii_lowercase(*byte) as u8 - } - } - - @iter - - is_ascii, - is_ascii_alphabetic, - is_ascii_uppercase, - is_ascii_lowercase, - is_ascii_alphanumeric, - is_ascii_digit, - is_ascii_hexdigit, - is_ascii_punctuation, - is_ascii_graphic, - is_ascii_whitespace, - is_ascii_control, -} - -macro_rules! repeat { - ($s: expr) => { - concat!($s, $s, $s, $s, $s, $s, $s, $s, $s, $s) - }; -} - -const SHORT: &str = "Alice's"; -const MEDIUM: &str = "Alice's Adventures in Wonderland"; -const LONG: &str = repeat!( - r#" - La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850) - Alice's Adventures in Wonderland (1865) - Phantasmagoria and Other Poems (1869) - Through the Looking-Glass, and What Alice Found There - (includes "Jabberwocky" and "The Walrus and the Carpenter") (1871) - The Hunting of the Snark (1876) - Rhyme? And Reason? (1883) – shares some contents with the 1869 collection, - including the long poem "Phantasmagoria" - A Tangled Tale (1885) - Sylvie and Bruno (1889) - Sylvie and Bruno Concluded (1893) - Pillow Problems (1893) - What the Tortoise Said to Achilles (1895) - Three Sunsets and Other Poems (1898) - The Manlet (1903)[106] -"# -); - -#[rustfmt::skip] -const ASCII_UPPERCASE_MAP: [u8; 256] = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', - b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', - b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', - b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', - b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G', - b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', - b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', - b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_', - b'`', - - b'A', b'B', b'C', b'D', b'E', b'F', b'G', - b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', - b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', - b'X', b'Y', b'Z', - - b'{', b'|', b'}', b'~', 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -]; - -enum AsciiCharacterClass { - C, // control - Cw, // control whitespace - W, // whitespace - D, // digit - L, // lowercase - Lx, // lowercase hex digit - U, // uppercase - Ux, // uppercase hex digit - P, // punctuation - N, // Non-ASCII -} -use self::AsciiCharacterClass::*; - -#[rustfmt::skip] -static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ -// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f - C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_ - C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_ - W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_ - D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_ - P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_ - U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_ - P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_ - L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_ - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, - N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, -]; - -const ASCII_PATH: &[u8] = b"home/kyubey/rust/build/x86_64-unknown-linux-gnu/stage0/lib:/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-tools/release/deps"; -const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; - -#[bench] -fn bench_ascii_escape_display_no_escape(b: &mut Bencher) { - let mut writer = String::with_capacity(8 * 1024); - - b.iter(move || { - writer.clear(); - let iter = ASCII_PATH.escape_ascii(); - write!(writer, "{}", iter).unwrap(); - writer.len() - }) -} - -#[bench] -fn bench_ascii_escape_display_mixed(b: &mut Bencher) { - let mut writer = String::with_capacity(8 * 1024); - - b.iter(move || { - writer.clear(); - let iter = RUST_INCANTATION.escape_ascii(); - write!(writer, "{}", iter).unwrap(); - writer.len() - }) -} diff --git a/library/core/benches/ascii/is_ascii.rs b/library/core/benches/ascii/is_ascii.rs deleted file mode 100644 index ced7084fb0e..00000000000 --- a/library/core/benches/ascii/is_ascii.rs +++ /dev/null @@ -1,123 +0,0 @@ -use test::{Bencher, black_box}; - -use super::{LONG, MEDIUM, SHORT}; - -macro_rules! benches { - ($( fn $name: ident($arg: ident: &[u8]) $body: block )+) => { - benches!(mod short SHORT[..] $($name $arg $body)+); - benches!(mod medium MEDIUM[..] $($name $arg $body)+); - benches!(mod long LONG[..] $($name $arg $body)+); - // Ensure we benchmark cases where the functions are called with strings - // that are not perfectly aligned or have a length which is not a - // multiple of size_of::() (or both) - benches!(mod unaligned_head_medium MEDIUM[1..] $($name $arg $body)+); - benches!(mod unaligned_tail_medium MEDIUM[..(MEDIUM.len() - 1)] $($name $arg $body)+); - benches!(mod unaligned_both_medium MEDIUM[1..(MEDIUM.len() - 1)] $($name $arg $body)+); - benches!(mod unaligned_head_long LONG[1..] $($name $arg $body)+); - benches!(mod unaligned_tail_long LONG[..(LONG.len() - 1)] $($name $arg $body)+); - benches!(mod unaligned_both_long LONG[1..(LONG.len() - 1)] $($name $arg $body)+); - }; - - (mod $mod_name: ident $input: ident [$range: expr] $($name: ident $arg: ident $body: block)+) => { - mod $mod_name { - use super::*; - $( - #[bench] - fn $name(bencher: &mut Bencher) { - bencher.bytes = $input[$range].len() as u64; - let mut vec = $input.as_bytes().to_vec(); - bencher.iter(|| { - let $arg: &[u8] = &black_box(&mut vec)[$range]; - black_box($body) - }) - } - )+ - } - }; -} - -benches! { - fn case00_libcore(bytes: &[u8]) { - bytes.is_ascii() - } - - fn case01_iter_all(bytes: &[u8]) { - bytes.iter().all(|b| b.is_ascii()) - } - - fn case02_align_to(bytes: &[u8]) { - is_ascii_align_to(bytes) - } - - fn case03_align_to_unrolled(bytes: &[u8]) { - is_ascii_align_to_unrolled(bytes) - } - - fn case04_while_loop(bytes: &[u8]) { - // Process chunks of 32 bytes at a time in the fast path to enable - // auto-vectorization and use of `pmovmskb`. Two 128-bit vector registers - // can be OR'd together and then the resulting vector can be tested for - // non-ASCII bytes. - const CHUNK_SIZE: usize = 32; - - let mut i = 0; - - while i + CHUNK_SIZE <= bytes.len() { - let chunk_end = i + CHUNK_SIZE; - - // Get LLVM to produce a `pmovmskb` instruction on x86-64 which - // creates a mask from the most significant bit of each byte. - // ASCII bytes are less than 128 (0x80), so their most significant - // bit is unset. - let mut count = 0; - while i < chunk_end { - count += bytes[i].is_ascii() as u8; - i += 1; - } - - // All bytes should be <= 127 so count is equal to chunk size. - if count != CHUNK_SIZE as u8 { - return false; - } - } - - // Process the remaining `bytes.len() % N` bytes. - let mut is_ascii = true; - while i < bytes.len() { - is_ascii &= bytes[i].is_ascii(); - i += 1; - } - - is_ascii - } -} - -// These are separate since it's easier to debug errors if they don't go through -// macro expansion first. -fn is_ascii_align_to(bytes: &[u8]) -> bool { - if bytes.len() < core::mem::size_of::() { - return bytes.iter().all(|b| b.is_ascii()); - } - // SAFETY: transmuting a sequence of `u8` to `usize` is always fine - let (head, body, tail) = unsafe { bytes.align_to::() }; - head.iter().all(|b| b.is_ascii()) - && body.iter().all(|w| !contains_nonascii(*w)) - && tail.iter().all(|b| b.is_ascii()) -} - -fn is_ascii_align_to_unrolled(bytes: &[u8]) -> bool { - if bytes.len() < core::mem::size_of::() { - return bytes.iter().all(|b| b.is_ascii()); - } - // SAFETY: transmuting a sequence of `u8` to `[usize; 2]` is always fine - let (head, body, tail) = unsafe { bytes.align_to::<[usize; 2]>() }; - head.iter().all(|b| b.is_ascii()) - && body.iter().all(|w| !contains_nonascii(w[0] | w[1])) - && tail.iter().all(|b| b.is_ascii()) -} - -#[inline] -fn contains_nonascii(v: usize) -> bool { - const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; core::mem::size_of::()]); - (NONASCII_MASK & v) != 0 -} diff --git a/library/core/benches/char/methods.rs b/library/core/benches/char/methods.rs deleted file mode 100644 index ed71920a4fc..00000000000 --- a/library/core/benches/char/methods.rs +++ /dev/null @@ -1,89 +0,0 @@ -use test::{Bencher, black_box}; - -const CHARS: [char; 9] = ['0', 'x', '2', '5', 'A', 'f', '7', '8', '9']; -const RADIX: [u32; 5] = [2, 8, 10, 16, 32]; - -#[bench] -fn bench_to_digit_radix_2(b: &mut Bencher) { - b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(2)).min()) -} - -#[bench] -fn bench_to_digit_radix_10(b: &mut Bencher) { - b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(10)).min()) -} - -#[bench] -fn bench_to_digit_radix_16(b: &mut Bencher) { - b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(16)).min()) -} - -#[bench] -fn bench_to_digit_radix_36(b: &mut Bencher) { - b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(36)).min()) -} - -#[bench] -fn bench_to_digit_radix_var(b: &mut Bencher) { - b.iter(|| { - CHARS - .iter() - .cycle() - .zip(RADIX.iter().cycle()) - .take(10_000) - .map(|(c, radix)| black_box(c).to_digit(*radix)) - .min() - }) -} - -#[bench] -fn bench_to_ascii_uppercase(b: &mut Bencher) { - b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_ascii_uppercase()).min()) -} - -#[bench] -fn bench_to_ascii_lowercase(b: &mut Bencher) { - b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_ascii_lowercase()).min()) -} - -#[bench] -fn bench_ascii_mix_to_uppercase(b: &mut Bencher) { - b.iter(|| { - (0..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_uppercase()).count() - }) -} - -#[bench] -fn bench_ascii_mix_to_lowercase(b: &mut Bencher) { - b.iter(|| { - (0..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_lowercase()).count() - }) -} - -#[bench] -fn bench_ascii_char_to_uppercase(b: &mut Bencher) { - b.iter(|| { - (0..=127).cycle().take(10_000).map(|b| black_box(char::from(b)).to_uppercase()).count() - }) -} - -#[bench] -fn bench_ascii_char_to_lowercase(b: &mut Bencher) { - b.iter(|| { - (0..=127).cycle().take(10_000).map(|b| black_box(char::from(b)).to_lowercase()).count() - }) -} - -#[bench] -fn bench_non_ascii_char_to_uppercase(b: &mut Bencher) { - b.iter(|| { - (128..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_uppercase()).count() - }) -} - -#[bench] -fn bench_non_ascii_char_to_lowercase(b: &mut Bencher) { - b.iter(|| { - (128..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_lowercase()).count() - }) -} diff --git a/library/core/benches/char/mod.rs b/library/core/benches/char/mod.rs deleted file mode 100644 index 9ca51a76847..00000000000 --- a/library/core/benches/char/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod methods; diff --git a/library/core/benches/fmt.rs b/library/core/benches/fmt.rs deleted file mode 100644 index ed478b0f1e0..00000000000 --- a/library/core/benches/fmt.rs +++ /dev/null @@ -1,165 +0,0 @@ -use std::fmt::{self, Write as FmtWrite}; -use std::io::{self, Write as IoWrite}; - -use test::{Bencher, black_box}; - -#[bench] -fn write_vec_value(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = Vec::new(); - for _ in 0..1000 { - mem.write_all(black_box("abc").as_bytes()).unwrap(); - } - }); -} - -#[bench] -fn write_vec_ref(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = Vec::new(); - let wr = &mut mem as &mut dyn io::Write; - for _ in 0..1000 { - wr.write_all(black_box("abc").as_bytes()).unwrap(); - } - }); -} - -#[bench] -fn write_vec_macro1(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = Vec::new(); - let wr = &mut mem as &mut dyn io::Write; - for _ in 0..1000 { - write!(wr, "{}", black_box("abc")).unwrap(); - } - }); -} - -#[bench] -fn write_vec_macro2(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = Vec::new(); - let wr = &mut mem as &mut dyn io::Write; - for _ in 0..1000 { - write!(wr, "{}", black_box("abc")).unwrap(); - } - }); -} - -#[bench] -fn write_vec_macro_debug(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = Vec::new(); - let wr = &mut mem as &mut dyn io::Write; - for _ in 0..1000 { - write!(wr, "{:?}", black_box("☃")).unwrap(); - } - }); -} - -#[bench] -fn write_str_value(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = String::new(); - for _ in 0..1000 { - mem.write_str(black_box("abc")).unwrap(); - } - }); -} - -#[bench] -fn write_str_ref(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = String::new(); - let wr = &mut mem as &mut dyn fmt::Write; - for _ in 0..1000 { - wr.write_str(black_box("abc")).unwrap(); - } - }); -} - -#[bench] -fn write_str_macro1(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = String::new(); - for _ in 0..1000 { - write!(mem, "{}", black_box("abc")).unwrap(); - } - }); -} - -#[bench] -fn write_str_macro2(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = String::new(); - let wr = &mut mem as &mut dyn fmt::Write; - for _ in 0..1000 { - write!(wr, "{}", black_box("abc")).unwrap(); - } - }); -} - -#[bench] -fn write_str_macro_debug(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = String::new(); - let wr = &mut mem as &mut dyn fmt::Write; - for _ in 0..1000 { - write!(wr, "{:?}", black_box("☃")).unwrap(); - } - }); -} - -#[bench] -fn write_str_macro_debug_ascii(bh: &mut Bencher) { - bh.iter(|| { - let mut mem = String::new(); - let wr = &mut mem as &mut dyn fmt::Write; - for _ in 0..1000 { - write!(wr, "{:?}", black_box("Hello, World!")).unwrap(); - } - }); -} - -#[bench] -fn write_u128_max(bh: &mut Bencher) { - bh.iter(|| { - test::black_box(format!("{}", u128::MAX)); - }); -} - -#[bench] -fn write_u128_min(bh: &mut Bencher) { - bh.iter(|| { - let s = format!("{}", 0u128); - test::black_box(s); - }); -} - -#[bench] -fn write_u64_max(bh: &mut Bencher) { - bh.iter(|| { - test::black_box(format!("{}", u64::MAX)); - }); -} - -#[bench] -fn write_u64_min(bh: &mut Bencher) { - bh.iter(|| { - test::black_box(format!("{}", 0u64)); - }); -} - -#[bench] -fn write_u8_max(bh: &mut Bencher) { - bh.iter(|| { - test::black_box(format!("{}", u8::MAX)); - }); -} - -#[bench] -fn write_u8_min(bh: &mut Bencher) { - bh.iter(|| { - test::black_box(format!("{}", 0u8)); - }); -} diff --git a/library/core/benches/hash/mod.rs b/library/core/benches/hash/mod.rs deleted file mode 100644 index 4f2e152b695..00000000000 --- a/library/core/benches/hash/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod sip; diff --git a/library/core/benches/hash/sip.rs b/library/core/benches/hash/sip.rs deleted file mode 100644 index c6562d3c011..00000000000 --- a/library/core/benches/hash/sip.rs +++ /dev/null @@ -1,124 +0,0 @@ -#![allow(deprecated)] - -use core::hash::*; - -use test::{Bencher, black_box}; - -fn hash_bytes(mut s: H, x: &[u8]) -> u64 { - Hasher::write(&mut s, x); - s.finish() -} - -fn hash_with(mut st: H, x: &T) -> u64 { - x.hash(&mut st); - st.finish() -} - -fn hash(x: &T) -> u64 { - hash_with(SipHasher::new(), x) -} - -#[bench] -fn bench_str_under_8_bytes(b: &mut Bencher) { - let s = "foo"; - b.iter(|| { - assert_eq!(hash(&s), 16262950014981195938); - }) -} - -#[bench] -fn bench_str_of_8_bytes(b: &mut Bencher) { - let s = "foobar78"; - b.iter(|| { - assert_eq!(hash(&s), 4898293253460910787); - }) -} - -#[bench] -fn bench_str_over_8_bytes(b: &mut Bencher) { - let s = "foobarbaz0"; - b.iter(|| { - assert_eq!(hash(&s), 10581415515220175264); - }) -} - -#[bench] -fn bench_long_str(b: &mut Bencher) { - let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \ - incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \ - exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \ - irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \ - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \ - officia deserunt mollit anim id est laborum."; - b.iter(|| { - assert_eq!(hash(&s), 17717065544121360093); - }) -} - -#[bench] -fn bench_u32(b: &mut Bencher) { - let u = 162629500u32; - let u = black_box(u); - b.iter(|| hash(&u)); - b.bytes = 8; -} - -#[bench] -fn bench_u32_keyed(b: &mut Bencher) { - let u = 162629500u32; - let u = black_box(u); - let k1 = black_box(0x1); - let k2 = black_box(0x2); - b.iter(|| hash_with(SipHasher::new_with_keys(k1, k2), &u)); - b.bytes = 8; -} - -#[bench] -fn bench_u64(b: &mut Bencher) { - let u = 16262950014981195938u64; - let u = black_box(u); - b.iter(|| hash(&u)); - b.bytes = 8; -} - -#[bench] -fn bench_bytes_4(b: &mut Bencher) { - let data = black_box([b' '; 4]); - b.iter(|| hash_bytes(SipHasher::default(), &data)); - b.bytes = 4; -} - -#[bench] -fn bench_bytes_7(b: &mut Bencher) { - let data = black_box([b' '; 7]); - b.iter(|| hash_bytes(SipHasher::default(), &data)); - b.bytes = 7; -} - -#[bench] -fn bench_bytes_8(b: &mut Bencher) { - let data = black_box([b' '; 8]); - b.iter(|| hash_bytes(SipHasher::default(), &data)); - b.bytes = 8; -} - -#[bench] -fn bench_bytes_a_16(b: &mut Bencher) { - let data = black_box([b' '; 16]); - b.iter(|| hash_bytes(SipHasher::default(), &data)); - b.bytes = 16; -} - -#[bench] -fn bench_bytes_b_32(b: &mut Bencher) { - let data = black_box([b' '; 32]); - b.iter(|| hash_bytes(SipHasher::default(), &data)); - b.bytes = 32; -} - -#[bench] -fn bench_bytes_c_128(b: &mut Bencher) { - let data = black_box([b' '; 128]); - b.iter(|| hash_bytes(SipHasher::default(), &data)); - b.bytes = 128; -} diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs deleted file mode 100644 index e14f26b7290..00000000000 --- a/library/core/benches/iter.rs +++ /dev/null @@ -1,548 +0,0 @@ -use core::borrow::Borrow; -use core::iter::*; -use core::mem; -use core::num::Wrapping; -use core::ops::Range; - -use test::{Bencher, black_box}; - -#[bench] -fn bench_rposition(b: &mut Bencher) { - let it: Vec = (0..300).collect(); - b.iter(|| { - it.iter().rposition(|&x| x <= 150); - }); -} - -#[bench] -fn bench_skip_while(b: &mut Bencher) { - b.iter(|| { - let it = 0..100; - let mut sum = 0; - it.skip_while(|&x| { - sum += x; - sum < 4000 - }) - .all(|_| true); - }); -} - -#[bench] -fn bench_multiple_take(b: &mut Bencher) { - let mut it = (0..42).cycle(); - b.iter(|| { - let n = it.next().unwrap(); - for _ in 0..n { - it.clone().take(it.next().unwrap()).all(|_| true); - } - }); -} - -fn scatter(x: i32) -> i32 { - (x * 31) % 127 -} - -#[bench] -fn bench_max_by_key(b: &mut Bencher) { - b.iter(|| { - let it = 0..100; - it.map(black_box).max_by_key(|&x| scatter(x)) - }) -} - -// https://www.reddit.com/r/rust/comments/31syce/using_iterators_to_find_the_index_of_the_min_or/ -#[bench] -fn bench_max_by_key2(b: &mut Bencher) { - fn max_index_iter(array: &[i32]) -> usize { - array.iter().enumerate().max_by_key(|&(_, item)| item).unwrap().0 - } - - let mut data = vec![0; 1638]; - data[514] = 9999; - - b.iter(|| max_index_iter(&data)); -} - -#[bench] -fn bench_max(b: &mut Bencher) { - b.iter(|| { - let it = 0..100; - it.map(black_box).map(scatter).max() - }) -} - -#[bench] -fn bench_range_step_by_sum_reducible(b: &mut Bencher) { - let r = 0u32..1024; - b.iter(|| { - let r = black_box(r.clone()).step_by(8); - - let mut sum: u32 = 0; - for i in r { - sum += i; - } - - sum - }) -} - -#[bench] -fn bench_range_step_by_loop_u32(b: &mut Bencher) { - let r = 0..(u16::MAX as u32); - b.iter(|| { - let r = black_box(r.clone()).step_by(64); - - let mut sum: u32 = 0; - for i in r { - let i = i ^ i.wrapping_sub(1); - sum = sum.wrapping_add(i); - } - - sum - }) -} - -#[bench] -fn bench_range_step_by_fold_usize(b: &mut Bencher) { - let r: Range = 0..(u16::MAX as usize); - b.iter(|| { - let r = black_box(r.clone()); - r.step_by(64) - .map(|x: usize| x ^ (x.wrapping_sub(1))) - .fold(0usize, |acc, i| acc.wrapping_add(i)) - }) -} - -#[bench] -fn bench_range_step_by_fold_u16(b: &mut Bencher) { - let r: Range = 0..u16::MAX; - b.iter(|| { - let r = black_box(r.clone()); - r.step_by(64).map(|x: u16| x ^ (x.wrapping_sub(1))).fold(0u16, |acc, i| acc.wrapping_add(i)) - }) -} - -pub fn copy_zip(xs: &[u8], ys: &mut [u8]) { - for (a, b) in ys.iter_mut().zip(xs) { - *a = *b; - } -} - -pub fn add_zip(xs: &[f32], ys: &mut [f32]) { - for (a, b) in ys.iter_mut().zip(xs) { - *a += *b; - } -} - -#[bench] -fn bench_zip_copy(b: &mut Bencher) { - let source = vec![0u8; 16 * 1024]; - let mut dst = black_box(vec![0u8; 16 * 1024]); - b.iter(|| copy_zip(&source, &mut dst)) -} - -#[bench] -fn bench_zip_add(b: &mut Bencher) { - let source = vec![1.; 16 * 1024]; - let mut dst = vec![0.; 16 * 1024]; - b.iter(|| add_zip(&source, &mut dst)); -} - -/// `Iterator::for_each` implemented as a plain loop. -fn for_each_loop(iter: I, mut f: F) -where - I: Iterator, - F: FnMut(I::Item), -{ - for item in iter { - f(item); - } -} - -/// `Iterator::for_each` implemented with `fold` for internal iteration. -/// (except when `by_ref()` effectively disables that optimization.) -fn for_each_fold(iter: I, mut f: F) -where - I: Iterator, - F: FnMut(I::Item), -{ - iter.fold((), move |(), item| f(item)); -} - -#[bench] -fn bench_for_each_chain_loop(b: &mut Bencher) { - b.iter(|| { - let mut acc = 0; - let iter = (0i64..1000000).chain(0..1000000).map(black_box); - for_each_loop(iter, |x| acc += x); - acc - }); -} - -#[bench] -fn bench_for_each_chain_fold(b: &mut Bencher) { - b.iter(|| { - let mut acc = 0; - let iter = (0i64..1000000).chain(0..1000000).map(black_box); - for_each_fold(iter, |x| acc += x); - acc - }); -} - -#[bench] -fn bench_for_each_chain_ref_fold(b: &mut Bencher) { - b.iter(|| { - let mut acc = 0; - let mut iter = (0i64..1000000).chain(0..1000000).map(black_box); - for_each_fold(iter.by_ref(), |x| acc += x); - acc - }); -} - -/// Helper to benchmark `sum` for iterators taken by value which -/// can optimize `fold`, and by reference which cannot. -macro_rules! bench_sums { - ($bench_sum:ident, $bench_ref_sum:ident, $iter:expr) => { - #[bench] - fn $bench_sum(b: &mut Bencher) { - b.iter(|| -> i64 { $iter.map(black_box).sum() }); - } - - #[bench] - fn $bench_ref_sum(b: &mut Bencher) { - b.iter(|| -> i64 { $iter.map(black_box).by_ref().sum() }); - } - }; -} - -bench_sums! { - bench_flat_map_sum, - bench_flat_map_ref_sum, - (0i64..1000).flat_map(|x| x..x+1000) -} - -bench_sums! { - bench_flat_map_chain_sum, - bench_flat_map_chain_ref_sum, - (0i64..1000000).flat_map(|x| once(x).chain(once(x))) -} - -bench_sums! { - bench_enumerate_sum, - bench_enumerate_ref_sum, - (0i64..1000000).enumerate().map(|(i, x)| x * i as i64) -} - -bench_sums! { - bench_enumerate_chain_sum, - bench_enumerate_chain_ref_sum, - (0i64..1000000).chain(0..1000000).enumerate().map(|(i, x)| x * i as i64) -} - -bench_sums! { - bench_filter_sum, - bench_filter_ref_sum, - (0i64..1000000).filter(|x| x % 3 == 0) -} - -bench_sums! { - bench_filter_chain_sum, - bench_filter_chain_ref_sum, - (0i64..1000000).chain(0..1000000).filter(|x| x % 3 == 0) -} - -bench_sums! { - bench_filter_map_sum, - bench_filter_map_ref_sum, - (0i64..1000000).filter_map(|x| x.checked_mul(x)) -} - -bench_sums! { - bench_filter_map_chain_sum, - bench_filter_map_chain_ref_sum, - (0i64..1000000).chain(0..1000000).filter_map(|x| x.checked_mul(x)) -} - -bench_sums! { - bench_fuse_sum, - bench_fuse_ref_sum, - (0i64..1000000).fuse() -} - -bench_sums! { - bench_fuse_chain_sum, - bench_fuse_chain_ref_sum, - (0i64..1000000).chain(0..1000000).fuse() -} - -bench_sums! { - bench_inspect_sum, - bench_inspect_ref_sum, - (0i64..1000000).inspect(|_| {}) -} - -bench_sums! { - bench_inspect_chain_sum, - bench_inspect_chain_ref_sum, - (0i64..1000000).chain(0..1000000).inspect(|_| {}) -} - -bench_sums! { - bench_peekable_sum, - bench_peekable_ref_sum, - (0i64..1000000).peekable() -} - -bench_sums! { - bench_peekable_chain_sum, - bench_peekable_chain_ref_sum, - (0i64..1000000).chain(0..1000000).peekable() -} - -bench_sums! { - bench_skip_sum, - bench_skip_ref_sum, - (0i64..1000000).skip(1000) -} - -bench_sums! { - bench_skip_chain_sum, - bench_skip_chain_ref_sum, - (0i64..1000000).chain(0..1000000).skip(1000) -} - -bench_sums! { - bench_skip_while_sum, - bench_skip_while_ref_sum, - (0i64..1000000).skip_while(|&x| x < 1000) -} - -bench_sums! { - bench_skip_while_chain_sum, - bench_skip_while_chain_ref_sum, - (0i64..1000000).chain(0..1000000).skip_while(|&x| x < 1000) -} - -bench_sums! { - bench_take_while_chain_sum, - bench_take_while_chain_ref_sum, - (0i64..1000000).chain(1000000..).take_while(|&x| x < 1111111) -} - -bench_sums! { - bench_cycle_take_sum, - bench_cycle_take_ref_sum, - (0..10000).cycle().take(1000000) -} - -bench_sums! { - bench_cycle_skip_take_sum, - bench_cycle_skip_take_ref_sum, - (0..100000).cycle().skip(1000000).take(1000000) -} - -bench_sums! { - bench_cycle_take_skip_sum, - bench_cycle_take_skip_ref_sum, - (0..100000).cycle().take(1000000).skip(100000) -} - -bench_sums! { - bench_skip_cycle_skip_zip_add_sum, - bench_skip_cycle_skip_zip_add_ref_sum, - (0..100000).skip(100).cycle().skip(100) - .zip((0..100000).cycle().skip(10)) - .map(|(a,b)| a+b) - .skip(100000) - .take(1000000) -} - -// Checks whether Skip> is as fast as Zip, Skip>, from -// https://users.rust-lang.org/t/performance-difference-between-iterator-zip-and-skip-order/15743 -#[bench] -fn bench_zip_then_skip(b: &mut Bencher) { - let v: Vec<_> = (0..100_000).collect(); - let t: Vec<_> = (0..100_000).collect(); - - b.iter(|| { - let s = v - .iter() - .zip(t.iter()) - .skip(10000) - .take_while(|t| *t.0 < 10100) - .map(|(a, b)| *a + *b) - .sum::(); - assert_eq!(s, 2009900); - }); -} -#[bench] -fn bench_skip_then_zip(b: &mut Bencher) { - let v: Vec<_> = (0..100_000).collect(); - let t: Vec<_> = (0..100_000).collect(); - - b.iter(|| { - let s = v - .iter() - .skip(10000) - .zip(t.iter().skip(10000)) - .take_while(|t| *t.0 < 10100) - .map(|(a, b)| *a + *b) - .sum::(); - assert_eq!(s, 2009900); - }); -} - -#[bench] -fn bench_skip_trusted_random_access(b: &mut Bencher) { - let v: Vec = black_box(vec![42; 10000]); - let mut sink = [0; 10000]; - - b.iter(|| { - for (val, idx) in v.iter().skip(8).zip(0..10000) { - sink[idx] += val; - } - sink - }); -} - -#[bench] -fn bench_filter_count(b: &mut Bencher) { - b.iter(|| (0i64..1000000).map(black_box).filter(|x| x % 3 == 0).count()) -} - -#[bench] -fn bench_filter_ref_count(b: &mut Bencher) { - b.iter(|| (0i64..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count()) -} - -#[bench] -fn bench_filter_chain_count(b: &mut Bencher) { - b.iter(|| (0i64..1000000).chain(0..1000000).map(black_box).filter(|x| x % 3 == 0).count()) -} - -#[bench] -fn bench_filter_chain_ref_count(b: &mut Bencher) { - b.iter(|| { - (0i64..1000000).chain(0..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count() - }) -} - -#[bench] -fn bench_partial_cmp(b: &mut Bencher) { - b.iter(|| (0..100000).map(black_box).partial_cmp((0..100000).map(black_box))) -} - -#[bench] -fn bench_chain_partial_cmp(b: &mut Bencher) { - b.iter(|| { - (0..50000).chain(50000..100000).map(black_box).partial_cmp((0..100000).map(black_box)) - }) -} - -#[bench] -fn bench_lt(b: &mut Bencher) { - b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box))) -} - -#[bench] -fn bench_trusted_random_access_adapters(b: &mut Bencher) { - let vec1: Vec<_> = (0usize..100000).collect(); - let vec2 = black_box(vec1.clone()); - b.iter(|| { - let mut iter = vec1 - .iter() - .copied() - .enumerate() - .map(|(idx, e)| idx.wrapping_add(e)) - .zip(vec2.iter().copied()) - .map(|(a, b)| a.wrapping_add(b)) - .fuse(); - let mut acc: usize = 0; - let size = iter.size(); - for i in 0..size { - // SAFETY: TRA requirements are satisfied by 0..size iteration and then dropping the - // iterator. - acc = acc.wrapping_add(unsafe { iter.__iterator_get_unchecked(i) }); - } - acc - }) -} - -/// Exercises the iter::Copied specialization for slice::Iter -#[bench] -fn bench_next_chunk_copied(b: &mut Bencher) { - let v = vec![1u8; 1024]; - - b.iter(|| { - let mut iter = black_box(&v).iter().copied(); - let mut acc = Wrapping(0); - // This uses a while-let loop to side-step the TRA specialization in ArrayChunks - while let Ok(chunk) = iter.next_chunk::<{ mem::size_of::() }>() { - let d = u64::from_ne_bytes(chunk); - acc += Wrapping(d.rotate_left(7).wrapping_add(1)); - } - acc - }) -} - -/// Exercises the TrustedRandomAccess specialization in ArrayChunks -#[bench] -#[allow(noop_method_call)] -fn bench_next_chunk_trusted_random_access(b: &mut Bencher) { - let v = vec![1u8; 1024]; - - b.iter(|| { - black_box(&v) - .iter() - // this shows that we're not relying on the slice::Iter specialization in Copied - .map(|b| *b.borrow()) - .array_chunks::<{ mem::size_of::() }>() - .map(|ary| { - let d = u64::from_ne_bytes(ary); - Wrapping(d.rotate_left(7).wrapping_add(1)) - }) - .sum::>() - }) -} - -#[bench] -fn bench_next_chunk_filter_even(b: &mut Bencher) { - let a = (0..1024).next_chunk::<1024>().unwrap(); - - b.iter(|| black_box(&a).iter().filter(|&&i| i % 2 == 0).next_chunk::<32>()) -} - -#[bench] -fn bench_next_chunk_filter_predictably_true(b: &mut Bencher) { - let a = (0..1024).next_chunk::<1024>().unwrap(); - - b.iter(|| black_box(&a).iter().filter(|&&i| i < 100).next_chunk::<32>()) -} - -#[bench] -fn bench_next_chunk_filter_mostly_false(b: &mut Bencher) { - let a = (0..1024).next_chunk::<1024>().unwrap(); - - b.iter(|| black_box(&a).iter().filter(|&&i| i > 900).next_chunk::<32>()) -} - -#[bench] -fn bench_next_chunk_filter_map_even(b: &mut Bencher) { - let a = (0..1024).next_chunk::<1024>().unwrap(); - - b.iter(|| black_box(&a).iter().filter_map(|&i| (i % 2 == 0).then(|| i)).next_chunk::<32>()) -} - -#[bench] -fn bench_next_chunk_filter_map_predictably_true(b: &mut Bencher) { - let a = (0..1024).next_chunk::<1024>().unwrap(); - - b.iter(|| black_box(&a).iter().filter_map(|&i| (i < 100).then(|| i)).next_chunk::<32>()) -} - -#[bench] -fn bench_next_chunk_filter_map_mostly_false(b: &mut Bencher) { - let a = (0..1024).next_chunk::<1024>().unwrap(); - - b.iter(|| black_box(&a).iter().filter_map(|&i| (i > 900).then(|| i)).next_chunk::<32>()) -} diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs deleted file mode 100644 index 32d15c386cb..00000000000 --- a/library/core/benches/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -// wasm32 does not support benches (no time). -#![cfg(not(target_arch = "wasm32"))] -// Disabling in Miri as these would take too long. -#![cfg(not(miri))] -#![feature(flt2dec)] -#![feature(test)] -#![feature(trusted_random_access)] -#![feature(iter_array_chunks)] -#![feature(iter_next_chunk)] -#![feature(iter_advance_by)] - -extern crate test; - -mod any; -mod array; -mod ascii; -mod char; -mod fmt; -mod hash; -mod iter; -mod net; -mod num; -mod ops; -mod pattern; -mod slice; -mod str; -mod tuple; - -/// Returns a `rand::Rng` seeded with a consistent seed. -/// -/// This is done to avoid introducing nondeterminism in benchmark results. -fn bench_rng() -> rand_xorshift::XorShiftRng { - const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - rand::SeedableRng::from_seed(SEED) -} diff --git a/library/core/benches/net/addr_parser.rs b/library/core/benches/net/addr_parser.rs deleted file mode 100644 index bbf2ea3eb97..00000000000 --- a/library/core/benches/net/addr_parser.rs +++ /dev/null @@ -1,78 +0,0 @@ -use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; -use core::str::FromStr; - -use test::{Bencher, black_box}; - -const IPV4_STR: &str = "192.168.0.1"; -const IPV4_STR_PORT: &str = "192.168.0.1:8080"; - -const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; -const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; -const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; -const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; -const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080"; - -#[bench] -fn bench_parse_ipv4(b: &mut Bencher) { - b.iter(|| Ipv4Addr::from_str(black_box(IPV4_STR))); -} - -#[bench] -fn bench_parse_ipv6_full(b: &mut Bencher) { - b.iter(|| Ipv6Addr::from_str(black_box(IPV6_STR_FULL))); -} - -#[bench] -fn bench_parse_ipv6_compress(b: &mut Bencher) { - b.iter(|| Ipv6Addr::from_str(black_box(IPV6_STR_COMPRESS))); -} - -#[bench] -fn bench_parse_ipv6_v4(b: &mut Bencher) { - b.iter(|| Ipv6Addr::from_str(black_box(IPV6_STR_V4))); -} - -#[bench] -fn bench_parse_ipaddr_v4(b: &mut Bencher) { - b.iter(|| IpAddr::from_str(black_box(IPV4_STR))); -} - -#[bench] -fn bench_parse_ipaddr_v6_full(b: &mut Bencher) { - b.iter(|| IpAddr::from_str(black_box(IPV6_STR_FULL))); -} - -#[bench] -fn bench_parse_ipaddr_v6_compress(b: &mut Bencher) { - b.iter(|| IpAddr::from_str(black_box(IPV6_STR_COMPRESS))); -} - -#[bench] -fn bench_parse_ipaddr_v6_v4(b: &mut Bencher) { - b.iter(|| IpAddr::from_str(black_box(IPV6_STR_V4))); -} - -#[bench] -fn bench_parse_socket_v4(b: &mut Bencher) { - b.iter(|| SocketAddrV4::from_str(black_box(IPV4_STR_PORT))); -} - -#[bench] -fn bench_parse_socket_v6(b: &mut Bencher) { - b.iter(|| SocketAddrV6::from_str(black_box(IPV6_STR_PORT))); -} - -#[bench] -fn bench_parse_socket_v6_scope_id(b: &mut Bencher) { - b.iter(|| SocketAddrV6::from_str(black_box(IPV6_STR_PORT_SCOPE_ID))); -} - -#[bench] -fn bench_parse_socketaddr_v4(b: &mut Bencher) { - b.iter(|| SocketAddr::from_str(black_box(IPV4_STR_PORT))); -} - -#[bench] -fn bench_parse_socketaddr_v6(b: &mut Bencher) { - b.iter(|| SocketAddr::from_str(black_box(IPV6_STR_PORT))); -} diff --git a/library/core/benches/net/mod.rs b/library/core/benches/net/mod.rs deleted file mode 100644 index c29aed46ccd..00000000000 --- a/library/core/benches/net/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod addr_parser; diff --git a/library/core/benches/num/dec2flt/mod.rs b/library/core/benches/num/dec2flt/mod.rs deleted file mode 100644 index bad211f240c..00000000000 --- a/library/core/benches/num/dec2flt/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -use test::{Bencher, black_box}; - -#[bench] -fn bench_0(b: &mut Bencher) { - b.iter(|| black_box("0.0").parse::()); -} - -#[bench] -fn bench_42(b: &mut Bencher) { - b.iter(|| black_box("42").parse::()); -} - -#[bench] -fn bench_huge_int(b: &mut Bencher) { - // 2^128 - 1 - b.iter(|| black_box("170141183460469231731687303715884105727").parse::()); -} - -#[bench] -fn bench_short_decimal(b: &mut Bencher) { - b.iter(|| black_box("1234.5678").parse::()); -} - -#[bench] -fn bench_pi_long(b: &mut Bencher) { - b.iter(|| black_box("3.14159265358979323846264338327950288").parse::()); -} - -#[bench] -fn bench_pi_short(b: &mut Bencher) { - b.iter(|| black_box("3.141592653589793").parse::()) -} - -#[bench] -fn bench_1e150(b: &mut Bencher) { - b.iter(|| black_box("1e150").parse::()); -} - -#[bench] -fn bench_long_decimal_and_exp(b: &mut Bencher) { - b.iter(|| black_box("727501488517303786137132964064381141071e-123").parse::()); -} - -#[bench] -fn bench_min_subnormal(b: &mut Bencher) { - b.iter(|| black_box("5e-324").parse::()); -} - -#[bench] -fn bench_min_normal(b: &mut Bencher) { - b.iter(|| black_box("2.2250738585072014e-308").parse::()); -} - -#[bench] -fn bench_max(b: &mut Bencher) { - b.iter(|| black_box("1.7976931348623157e308").parse::()); -} diff --git a/library/core/benches/num/flt2dec/mod.rs b/library/core/benches/num/flt2dec/mod.rs deleted file mode 100644 index 428d0bbbbfb..00000000000 --- a/library/core/benches/num/flt2dec/mod.rs +++ /dev/null @@ -1,36 +0,0 @@ -mod strategy { - mod dragon; - mod grisu; -} - -use core::num::flt2dec::{DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, decode}; -use std::io::Write; - -use test::{Bencher, black_box}; - -pub fn decode_finite(v: T) -> Decoded { - match decode(v).1 { - FullDecoded::Finite(decoded) => decoded, - full_decoded => panic!("expected finite, got {full_decoded:?} instead"), - } -} - -#[bench] -fn bench_small_shortest(b: &mut Bencher) { - let mut buf = Vec::with_capacity(20); - - b.iter(|| { - buf.clear(); - write!(black_box(&mut buf), "{}", black_box(3.1415926f64)).unwrap() - }); -} - -#[bench] -fn bench_big_shortest(b: &mut Bencher) { - let mut buf = Vec::with_capacity(300); - - b.iter(|| { - buf.clear(); - write!(black_box(&mut buf), "{}", black_box(f64::MAX)).unwrap() - }); -} diff --git a/library/core/benches/num/flt2dec/strategy/dragon.rs b/library/core/benches/num/flt2dec/strategy/dragon.rs deleted file mode 100644 index 45266971403..00000000000 --- a/library/core/benches/num/flt2dec/strategy/dragon.rs +++ /dev/null @@ -1,76 +0,0 @@ -use core::num::flt2dec::strategy::dragon::*; -use std::mem::MaybeUninit; - -use super::super::*; - -#[bench] -fn bench_small_shortest(b: &mut Bencher) { - let decoded = decode_finite(3.141592f64); - let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; - b.iter(|| { - format_shortest(black_box(&decoded), &mut buf); - }); -} - -#[bench] -fn bench_big_shortest(b: &mut Bencher) { - let decoded = decode_finite(f64::MAX); - let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; - b.iter(|| { - format_shortest(black_box(&decoded), &mut buf); - }); -} - -#[bench] -fn bench_small_exact_3(b: &mut Bencher) { - let decoded = decode_finite(3.141592f64); - let mut buf = [MaybeUninit::new(0); 3]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_big_exact_3(b: &mut Bencher) { - let decoded = decode_finite(f64::MAX); - let mut buf = [MaybeUninit::new(0); 3]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_small_exact_12(b: &mut Bencher) { - let decoded = decode_finite(3.141592f64); - let mut buf = [MaybeUninit::new(0); 12]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_big_exact_12(b: &mut Bencher) { - let decoded = decode_finite(f64::MAX); - let mut buf = [MaybeUninit::new(0); 12]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_small_exact_inf(b: &mut Bencher) { - let decoded = decode_finite(3.141592f64); - let mut buf = [MaybeUninit::new(0); 1024]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_big_exact_inf(b: &mut Bencher) { - let decoded = decode_finite(f64::MAX); - let mut buf = [MaybeUninit::new(0); 1024]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} diff --git a/library/core/benches/num/flt2dec/strategy/grisu.rs b/library/core/benches/num/flt2dec/strategy/grisu.rs deleted file mode 100644 index d20f9b02f7e..00000000000 --- a/library/core/benches/num/flt2dec/strategy/grisu.rs +++ /dev/null @@ -1,110 +0,0 @@ -use core::num::flt2dec::strategy::grisu::*; -use std::mem::MaybeUninit; - -use super::super::*; - -pub fn decode_finite(v: T) -> Decoded { - match decode(v).1 { - FullDecoded::Finite(decoded) => decoded, - full_decoded => panic!("expected finite, got {full_decoded:?} instead"), - } -} - -#[bench] -fn bench_small_shortest(b: &mut Bencher) { - let decoded = decode_finite(3.141592f64); - let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; - b.iter(|| { - format_shortest(black_box(&decoded), &mut buf); - }); -} - -#[bench] -fn bench_big_shortest(b: &mut Bencher) { - let decoded = decode_finite(f64::MAX); - let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; - b.iter(|| { - format_shortest(black_box(&decoded), &mut buf); - }); -} - -#[bench] -fn bench_small_exact_3(b: &mut Bencher) { - let decoded = decode_finite(3.141592f64); - let mut buf = [MaybeUninit::new(0); 3]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_big_exact_3(b: &mut Bencher) { - let decoded = decode_finite(f64::MAX); - let mut buf = [MaybeUninit::new(0); 3]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_small_exact_12(b: &mut Bencher) { - let decoded = decode_finite(3.141592f64); - let mut buf = [MaybeUninit::new(0); 12]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_big_exact_12(b: &mut Bencher) { - let decoded = decode_finite(f64::MAX); - let mut buf = [MaybeUninit::new(0); 12]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_small_exact_inf(b: &mut Bencher) { - let decoded = decode_finite(3.141592f64); - let mut buf = [MaybeUninit::new(0); 1024]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_big_exact_inf(b: &mut Bencher) { - let decoded = decode_finite(f64::MAX); - let mut buf = [MaybeUninit::new(0); 1024]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_one_exact_inf(b: &mut Bencher) { - let decoded = decode_finite(1.0); - let mut buf = [MaybeUninit::new(0); 1024]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_trailing_zero_exact_inf(b: &mut Bencher) { - let decoded = decode_finite(250.000000000000000000000000); - let mut buf = [MaybeUninit::new(0); 1024]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} - -#[bench] -fn bench_halfway_point_exact_inf(b: &mut Bencher) { - let decoded = decode_finite(1.00000000000000011102230246251565404236316680908203125); - let mut buf = [MaybeUninit::new(0); 1024]; - b.iter(|| { - format_exact(black_box(&decoded), &mut buf, i16::MIN); - }); -} diff --git a/library/core/benches/num/int_log/mod.rs b/library/core/benches/num/int_log/mod.rs deleted file mode 100644 index e5874ddf03b..00000000000 --- a/library/core/benches/num/int_log/mod.rs +++ /dev/null @@ -1,125 +0,0 @@ -use rand::Rng; -use test::{Bencher, black_box}; - -macro_rules! int_log10_bench { - ($t:ty, $predictable:ident, $random:ident, $random_small:ident) => { - #[bench] - fn $predictable(bench: &mut Bencher) { - bench.iter(|| { - for n in 0..(<$t>::BITS / 8) { - for i in 1..=(100 as $t) { - let x = black_box(i << (n * 8)); - black_box(x.ilog10()); - } - } - }); - } - - #[bench] - fn $random(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); - /* Exponentially distributed random numbers from the whole range of the type. */ - let numbers: Vec<$t> = (0..256) - .map(|_| { - let x = rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS); - if x != 0 { x } else { 1 } - }) - .collect(); - bench.iter(|| { - for x in &numbers { - black_box(black_box(x).ilog10()); - } - }); - } - - #[bench] - fn $random_small(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); - /* Exponentially distributed random numbers from the range 0..256. */ - let numbers: Vec<$t> = (0..256) - .map(|_| { - let x = (rng.gen::() >> rng.gen_range(0..u8::BITS)) as $t; - if x != 0 { x } else { 1 } - }) - .collect(); - bench.iter(|| { - for x in &numbers { - black_box(black_box(x).ilog10()); - } - }); - } - }; -} - -int_log10_bench! {u8, u8_log10_predictable, u8_log10_random, u8_log10_random_small} -int_log10_bench! {u16, u16_log10_predictable, u16_log10_random, u16_log10_random_small} -int_log10_bench! {u32, u32_log10_predictable, u32_log10_random, u32_log10_random_small} -int_log10_bench! {u64, u64_log10_predictable, u64_log10_random, u64_log10_random_small} -int_log10_bench! {u128, u128_log10_predictable, u128_log10_random, u128_log10_random_small} - -macro_rules! int_log_bench { - ($t:ty, $random:ident, $random_small:ident, $geometric:ident) => { - #[bench] - fn $random(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); - /* Exponentially distributed random numbers from the whole range of the type. */ - let numbers: Vec<$t> = (0..256) - .map(|_| { - let x = rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS); - if x >= 2 { x } else { 2 } - }) - .collect(); - bench.iter(|| { - for &b in &numbers { - for &x in &numbers { - black_box(black_box(x).ilog(b)); - } - } - }); - } - - #[bench] - fn $random_small(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); - /* Exponentially distributed random numbers from the range 0..256. */ - let numbers: Vec<$t> = (0..256) - .map(|_| { - let x = (rng.gen::() >> rng.gen_range(0..u8::BITS)) as $t; - if x >= 2 { x } else { 2 } - }) - .collect(); - bench.iter(|| { - for &b in &numbers { - for &x in &numbers { - black_box(black_box(x).ilog(b)); - } - } - }); - } - - #[bench] - fn $geometric(bench: &mut Bencher) { - let bases: [$t; 16] = [2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65]; - let base_and_numbers: Vec<($t, Vec<$t>)> = bases - .iter() - .map(|&b| { - let numbers = (0..=<$t>::MAX.ilog(b)).map(|exp| b.pow(exp)).collect(); - (b, numbers) - }) - .collect(); - bench.iter(|| { - for (b, numbers) in &base_and_numbers { - for &x in numbers { - black_box(black_box(x).ilog(black_box(*b))); - } - } - }); - } - }; -} - -int_log_bench! {u8, u8_log_random, u8_log_random_small, u8_log_geometric} -int_log_bench! {u16, u16_log_random, u16_log_random_small, u16_log_geometric} -int_log_bench! {u32, u32_log_random, u32_log_random_small, u32_log_geometric} -int_log_bench! {u64, u64_log_random, u64_log_random_small, u64_log_geometric} -int_log_bench! {u128, u128_log_random, u128_log_random_small, u128_log_geometric} diff --git a/library/core/benches/num/int_pow/mod.rs b/library/core/benches/num/int_pow/mod.rs deleted file mode 100644 index 46f47028d56..00000000000 --- a/library/core/benches/num/int_pow/mod.rs +++ /dev/null @@ -1,99 +0,0 @@ -use rand::Rng; -use test::{Bencher, black_box}; - -const ITERATIONS: usize = 128; // Uses an ITERATIONS * 20 Byte stack allocation -type IntType = i128; // Hardest native type to multiply -const EXPONENT_MAX: u32 = 31; -const MAX_BASE: IntType = 17; // +-17 ** 31 <= IntType::MAX - -macro_rules! pow_bench_template { - ($name:ident, $inner_macro:ident, $base_macro:ident) => { - #[bench] - fn $name(bench: &mut Bencher) { - // Frequent black_box calls can add latency and prevent optimizations, so for - // variable parameters we premake an array and pass the - // reference through black_box outside of the loop. - let mut rng = crate::bench_rng(); - let base_array: [IntType; ITERATIONS] = - core::array::from_fn(|_| rng.gen_range((-MAX_BASE..=MAX_BASE))); - let exp_array: [u32; ITERATIONS] = - core::array::from_fn(|_| rng.gen_range((0..=EXPONENT_MAX))); - - bench.iter(|| { - #[allow(unused, unused_mut)] - let mut base_iter = black_box(&base_array).into_iter(); - let mut exp_iter = black_box(&exp_array).into_iter(); - - (0..ITERATIONS).fold((0 as IntType, false), |acc, _| { - // Sometimes constants don't propagate all the way to the - // inside of the loop, so we call a custom expression every cycle - // rather than iter::repeat(CONST) - let base: IntType = $base_macro!(base_iter); - let exp: u32 = *exp_iter.next().unwrap(); - - let r: (IntType, bool) = $inner_macro!(base, exp); - (acc.0 ^ r.0, acc.1 ^ r.1) - }) - }); - } - }; -} - -// This may panic if it overflows. -macro_rules! inner_pow { - ($base:ident, $exp:ident) => { - ($base.pow($exp), false) - }; -} - -macro_rules! inner_wrapping { - ($base:ident, $exp:ident) => { - ($base.wrapping_pow($exp), false) - }; -} - -macro_rules! inner_overflowing { - ($base:ident, $exp:ident) => { - $base.overflowing_pow($exp) - }; -} - -// This will panic if it overflows. -macro_rules! inner_checked_unwrapped { - ($base:ident, $exp:ident) => { - ($base.checked_pow($exp).unwrap(), false) - }; -} - -macro_rules! inner_saturating { - ($base:ident, $exp:ident) => { - ($base.saturating_pow($exp), false) - }; -} - -macro_rules! make_const_base { - ($name:ident, $x:literal) => { - macro_rules! $name { - ($iter:ident) => { - $x - }; - } - }; -} - -make_const_base!(const_base_m7, -7); -make_const_base!(const_base_m8, -8); - -macro_rules! variable_base { - ($iter:ident) => { - *$iter.next().unwrap() - }; -} - -pow_bench_template!(pow_variable, inner_pow, variable_base); -pow_bench_template!(wrapping_pow_variable, inner_wrapping, variable_base); -pow_bench_template!(overflowing_pow_variable, inner_overflowing, variable_base); -pow_bench_template!(checked_pow_variable, inner_checked_unwrapped, variable_base); -pow_bench_template!(saturating_pow_variable, inner_saturating, variable_base); -pow_bench_template!(pow_m7, inner_pow, const_base_m7); -pow_bench_template!(pow_m8, inner_pow, const_base_m8); diff --git a/library/core/benches/num/int_sqrt/mod.rs b/library/core/benches/num/int_sqrt/mod.rs deleted file mode 100644 index e47b92e866e..00000000000 --- a/library/core/benches/num/int_sqrt/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -use rand::Rng; -use test::{Bencher, black_box}; - -macro_rules! int_sqrt_bench { - ($t:ty, $predictable:ident, $random:ident, $random_small:ident, $random_uniform:ident) => { - #[bench] - fn $predictable(bench: &mut Bencher) { - bench.iter(|| { - for n in 0..(<$t>::BITS / 8) { - for i in 1..=(100 as $t) { - let x = black_box(i << (n * 8)); - black_box(x.isqrt()); - } - } - }); - } - - #[bench] - fn $random(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); - /* Exponentially distributed random numbers from the whole range of the type. */ - let numbers: Vec<$t> = - (0..256).map(|_| rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS)).collect(); - bench.iter(|| { - for x in &numbers { - black_box(black_box(x).isqrt()); - } - }); - } - - #[bench] - fn $random_small(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); - /* Exponentially distributed random numbers from the range 0..256. */ - let numbers: Vec<$t> = - (0..256).map(|_| (rng.gen::() >> rng.gen_range(0..u8::BITS)) as $t).collect(); - bench.iter(|| { - for x in &numbers { - black_box(black_box(x).isqrt()); - } - }); - } - - #[bench] - fn $random_uniform(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); - /* Exponentially distributed random numbers from the whole range of the type. */ - let numbers: Vec<$t> = (0..256).map(|_| rng.gen::<$t>()).collect(); - bench.iter(|| { - for x in &numbers { - black_box(black_box(x).isqrt()); - } - }); - } - }; -} - -int_sqrt_bench! {u8, u8_sqrt_predictable, u8_sqrt_random, u8_sqrt_random_small, u8_sqrt_uniform} -int_sqrt_bench! {u16, u16_sqrt_predictable, u16_sqrt_random, u16_sqrt_random_small, u16_sqrt_uniform} -int_sqrt_bench! {u32, u32_sqrt_predictable, u32_sqrt_random, u32_sqrt_random_small, u32_sqrt_uniform} -int_sqrt_bench! {u64, u64_sqrt_predictable, u64_sqrt_random, u64_sqrt_random_small, u64_sqrt_uniform} -int_sqrt_bench! {u128, u128_sqrt_predictable, u128_sqrt_random, u128_sqrt_random_small, u128_sqrt_uniform} diff --git a/library/core/benches/num/mod.rs b/library/core/benches/num/mod.rs deleted file mode 100644 index b36100e59a9..00000000000 --- a/library/core/benches/num/mod.rs +++ /dev/null @@ -1,111 +0,0 @@ -mod dec2flt; -mod flt2dec; -mod int_log; -mod int_pow; -mod int_sqrt; - -use std::str::FromStr; - -use test::{Bencher, black_box}; - -const ASCII_NUMBERS: [&str; 19] = [ - "0", - "1", - "2", - "43", - "765", - "76567", - "987245987", - "-4aa32", - "1786235", - "8723095", - "f##5s", - "83638730", - "-2345", - "562aa43", - "-1", - "-0", - "abc", - "xyz", - "c0ffee", -]; - -macro_rules! from_str_bench { - ($mac:ident, $t:ty) => { - #[bench] - fn $mac(b: &mut Bencher) { - b.iter(|| { - ASCII_NUMBERS - .iter() - .cycle() - .take(5_000) - .filter_map(|s| <$t>::from_str(black_box(s)).ok()) - .max() - }) - } - }; -} - -macro_rules! from_str_radix_bench { - ($mac:ident, $t:ty, $radix:expr) => { - #[bench] - fn $mac(b: &mut Bencher) { - b.iter(|| { - ASCII_NUMBERS - .iter() - .cycle() - .take(5_000) - .filter_map(|s| <$t>::from_str_radix(black_box(s), $radix).ok()) - .max() - }) - } - }; -} - -from_str_bench!(bench_u8_from_str, u8); -from_str_radix_bench!(bench_u8_from_str_radix_2, u8, 2); -from_str_radix_bench!(bench_u8_from_str_radix_10, u8, 10); -from_str_radix_bench!(bench_u8_from_str_radix_16, u8, 16); -from_str_radix_bench!(bench_u8_from_str_radix_36, u8, 36); - -from_str_bench!(bench_u16_from_str, u16); -from_str_radix_bench!(bench_u16_from_str_radix_2, u16, 2); -from_str_radix_bench!(bench_u16_from_str_radix_10, u16, 10); -from_str_radix_bench!(bench_u16_from_str_radix_16, u16, 16); -from_str_radix_bench!(bench_u16_from_str_radix_36, u16, 36); - -from_str_bench!(bench_u32_from_str, u32); -from_str_radix_bench!(bench_u32_from_str_radix_2, u32, 2); -from_str_radix_bench!(bench_u32_from_str_radix_10, u32, 10); -from_str_radix_bench!(bench_u32_from_str_radix_16, u32, 16); -from_str_radix_bench!(bench_u32_from_str_radix_36, u32, 36); - -from_str_bench!(bench_u64_from_str, u64); -from_str_radix_bench!(bench_u64_from_str_radix_2, u64, 2); -from_str_radix_bench!(bench_u64_from_str_radix_10, u64, 10); -from_str_radix_bench!(bench_u64_from_str_radix_16, u64, 16); -from_str_radix_bench!(bench_u64_from_str_radix_36, u64, 36); - -from_str_bench!(bench_i8_from_str, i8); -from_str_radix_bench!(bench_i8_from_str_radix_2, i8, 2); -from_str_radix_bench!(bench_i8_from_str_radix_10, i8, 10); -from_str_radix_bench!(bench_i8_from_str_radix_16, i8, 16); -from_str_radix_bench!(bench_i8_from_str_radix_36, i8, 36); - -from_str_bench!(bench_i16_from_str, i16); -from_str_radix_bench!(bench_i16_from_str_radix_2, i16, 2); -from_str_radix_bench!(bench_i16_from_str_radix_10, i16, 10); -from_str_radix_bench!(bench_i16_from_str_radix_16, i16, 16); -from_str_radix_bench!(bench_i16_from_str_radix_36, i16, 36); - -from_str_bench!(bench_i32_from_str, i32); -from_str_radix_bench!(bench_i32_from_str_radix_2, i32, 2); -from_str_radix_bench!(bench_i32_from_str_radix_10, i32, 10); -from_str_radix_bench!(bench_i32_from_str_radix_16, i32, 16); -from_str_radix_bench!(bench_i32_from_str_radix_36, i32, 36); - -from_str_bench!(bench_i64_from_str, i64); -from_str_radix_bench!(bench_i64_from_str_radix_2, i64, 2); -from_str_radix_bench!(bench_i64_from_str_radix_10, i64, 10); -from_str_radix_bench!(bench_i64_from_str_radix_16, i64, 16); -from_str_radix_bench!(bench_i64_from_str_radix_36, i64, 36); diff --git a/library/core/benches/ops.rs b/library/core/benches/ops.rs deleted file mode 100644 index 3d0b3302957..00000000000 --- a/library/core/benches/ops.rs +++ /dev/null @@ -1,20 +0,0 @@ -use core::ops::*; - -use test::Bencher; - -// Overhead of dtors - -struct HasDtor { - _x: isize, -} - -impl Drop for HasDtor { - fn drop(&mut self) {} -} - -#[bench] -fn alloc_obj_with_dtor(b: &mut Bencher) { - b.iter(|| { - HasDtor { _x: 10 }; - }) -} diff --git a/library/core/benches/pattern.rs b/library/core/benches/pattern.rs deleted file mode 100644 index b0f8b39c22e..00000000000 --- a/library/core/benches/pattern.rs +++ /dev/null @@ -1,41 +0,0 @@ -use test::{Bencher, black_box}; - -#[bench] -fn starts_with_char(b: &mut Bencher) { - let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind"); - b.iter(|| { - for _ in 0..1024 { - black_box(text.starts_with('k')); - } - }) -} - -#[bench] -fn starts_with_str(b: &mut Bencher) { - let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind"); - b.iter(|| { - for _ in 0..1024 { - black_box(text.starts_with("k")); - } - }) -} - -#[bench] -fn ends_with_char(b: &mut Bencher) { - let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind"); - b.iter(|| { - for _ in 0..1024 { - black_box(text.ends_with('k')); - } - }) -} - -#[bench] -fn ends_with_str(b: &mut Bencher) { - let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind"); - b.iter(|| { - for _ in 0..1024 { - black_box(text.ends_with("k")); - } - }) -} diff --git a/library/core/benches/slice.rs b/library/core/benches/slice.rs deleted file mode 100644 index 29a66b62199..00000000000 --- a/library/core/benches/slice.rs +++ /dev/null @@ -1,173 +0,0 @@ -use core::ptr::NonNull; - -use test::{Bencher, black_box}; - -enum Cache { - L1, - L2, - L3, -} - -impl Cache { - fn size(&self) -> usize { - match self { - Cache::L1 => 1000, // 8kb - Cache::L2 => 10_000, // 80kb - Cache::L3 => 1_000_000, // 8Mb - } - } -} - -fn binary_search(b: &mut Bencher, cache: Cache, mapper: F) -where - F: Fn(usize) -> usize, -{ - let size = cache.size(); - let v = (0..size).map(&mapper).collect::>(); - let mut r = 0usize; - b.iter(move || { - // LCG constants from https://en.wikipedia.org/wiki/Numerical_Recipes. - r = r.wrapping_mul(1664525).wrapping_add(1013904223); - // Lookup the whole range to get 50% hits and 50% misses. - let i = mapper(r % size); - black_box(v.binary_search(&i).is_ok()); - }); -} - -fn binary_search_worst_case(b: &mut Bencher, cache: Cache) { - let size = cache.size(); - - let mut v = vec![0; size]; - let i = 1; - v[size - 1] = i; - b.iter(move || { - black_box(v.binary_search(&i).is_ok()); - }); -} - -#[bench] -fn binary_search_l1(b: &mut Bencher) { - binary_search(b, Cache::L1, |i| i * 2); -} - -#[bench] -fn binary_search_l2(b: &mut Bencher) { - binary_search(b, Cache::L2, |i| i * 2); -} - -#[bench] -fn binary_search_l3(b: &mut Bencher) { - binary_search(b, Cache::L3, |i| i * 2); -} - -#[bench] -fn binary_search_l1_with_dups(b: &mut Bencher) { - binary_search(b, Cache::L1, |i| i / 16 * 16); -} - -#[bench] -fn binary_search_l2_with_dups(b: &mut Bencher) { - binary_search(b, Cache::L2, |i| i / 16 * 16); -} - -#[bench] -fn binary_search_l3_with_dups(b: &mut Bencher) { - binary_search(b, Cache::L3, |i| i / 16 * 16); -} - -#[bench] -fn binary_search_l1_worst_case(b: &mut Bencher) { - binary_search_worst_case(b, Cache::L1); -} - -#[bench] -fn binary_search_l2_worst_case(b: &mut Bencher) { - binary_search_worst_case(b, Cache::L2); -} - -#[bench] -fn binary_search_l3_worst_case(b: &mut Bencher) { - binary_search_worst_case(b, Cache::L3); -} - -#[derive(Clone)] -struct Rgb(#[allow(dead_code)] u8, #[allow(dead_code)] u8, #[allow(dead_code)] u8); - -impl Rgb { - fn gen(i: usize) -> Self { - Rgb(i as u8, (i as u8).wrapping_add(7), (i as u8).wrapping_add(42)) - } -} - -macro_rules! rotate { - ($fn:ident, $n:expr, $mapper:expr) => { - #[bench] - fn $fn(b: &mut Bencher) { - let mut x = (0usize..$n).map(&$mapper).collect::>(); - b.iter(|| { - for s in 0..x.len() { - x[..].rotate_right(s); - } - black_box(x[0].clone()) - }) - } - }; -} - -rotate!(rotate_u8, 32, |i| i as u8); -rotate!(rotate_rgb, 32, Rgb::gen); -rotate!(rotate_usize, 32, |i| i); -rotate!(rotate_16_usize_4, 16, |i| [i; 4]); -rotate!(rotate_16_usize_5, 16, |i| [i; 5]); -rotate!(rotate_64_usize_4, 64, |i| [i; 4]); -rotate!(rotate_64_usize_5, 64, |i| [i; 5]); - -macro_rules! swap_with_slice { - ($fn:ident, $n:expr, $mapper:expr) => { - #[bench] - fn $fn(b: &mut Bencher) { - let mut x = (0usize..$n).map(&$mapper).collect::>(); - let mut y = ($n..($n * 2)).map(&$mapper).collect::>(); - let mut skip = 0; - b.iter(|| { - for _ in 0..32 { - x[skip..].swap_with_slice(&mut y[..($n - skip)]); - skip = black_box(skip + 1) % 8; - } - black_box((x[$n / 3].clone(), y[$n * 2 / 3].clone())) - }) - } - }; -} - -swap_with_slice!(swap_with_slice_u8_30, 30, |i| i as u8); -swap_with_slice!(swap_with_slice_u8_3000, 3000, |i| i as u8); -swap_with_slice!(swap_with_slice_rgb_30, 30, Rgb::gen); -swap_with_slice!(swap_with_slice_rgb_3000, 3000, Rgb::gen); -swap_with_slice!(swap_with_slice_usize_30, 30, |i| i); -swap_with_slice!(swap_with_slice_usize_3000, 3000, |i| i); -swap_with_slice!(swap_with_slice_4x_usize_30, 30, |i| [i; 4]); -swap_with_slice!(swap_with_slice_4x_usize_3000, 3000, |i| [i; 4]); -swap_with_slice!(swap_with_slice_5x_usize_30, 30, |i| [i; 5]); -swap_with_slice!(swap_with_slice_5x_usize_3000, 3000, |i| [i; 5]); - -#[bench] -fn fill_byte_sized(b: &mut Bencher) { - #[derive(Copy, Clone)] - struct NewType(#[allow(dead_code)] u8); - - let mut ary = [NewType(0); 1024]; - - b.iter(|| { - let slice = &mut ary[..]; - black_box(slice.fill(black_box(NewType(42)))); - }); -} - -// Tests the ability of the compiler to recognize that only the last slice item is needed -// based on issue #106288 -#[bench] -fn fold_to_last(b: &mut Bencher) { - let slice: &[i32] = &[0; 1024]; - b.iter(|| black_box(slice).iter().fold(None, |_, r| Some(NonNull::from(r)))); -} diff --git a/library/core/benches/str.rs b/library/core/benches/str.rs deleted file mode 100644 index 2f7d9d56a70..00000000000 --- a/library/core/benches/str.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::str; - -use test::{Bencher, black_box}; - -mod char_count; -mod corpora; -mod debug; -mod iter; - -#[bench] -fn str_validate_emoji(b: &mut Bencher) { - b.iter(|| str::from_utf8(black_box(corpora::emoji::LARGE.as_bytes()))); -} diff --git a/library/core/benches/str/char_count.rs b/library/core/benches/str/char_count.rs deleted file mode 100644 index 343e23dcf41..00000000000 --- a/library/core/benches/str/char_count.rs +++ /dev/null @@ -1,108 +0,0 @@ -use test::{Bencher, black_box}; - -use super::corpora::*; - -macro_rules! define_benches { - ($( fn $name: ident($arg: ident: &str) $body: block )+) => { - define_benches!(mod en_tiny, en::TINY, $($name $arg $body)+); - define_benches!(mod en_small, en::SMALL, $($name $arg $body)+); - define_benches!(mod en_medium, en::MEDIUM, $($name $arg $body)+); - define_benches!(mod en_large, en::LARGE, $($name $arg $body)+); - define_benches!(mod en_huge, en::HUGE, $($name $arg $body)+); - - define_benches!(mod zh_tiny, zh::TINY, $($name $arg $body)+); - define_benches!(mod zh_small, zh::SMALL, $($name $arg $body)+); - define_benches!(mod zh_medium, zh::MEDIUM, $($name $arg $body)+); - define_benches!(mod zh_large, zh::LARGE, $($name $arg $body)+); - define_benches!(mod zh_huge, zh::HUGE, $($name $arg $body)+); - - define_benches!(mod ru_tiny, ru::TINY, $($name $arg $body)+); - define_benches!(mod ru_small, ru::SMALL, $($name $arg $body)+); - define_benches!(mod ru_medium, ru::MEDIUM, $($name $arg $body)+); - define_benches!(mod ru_large, ru::LARGE, $($name $arg $body)+); - define_benches!(mod ru_huge, ru::HUGE, $($name $arg $body)+); - - define_benches!(mod emoji_tiny, emoji::TINY, $($name $arg $body)+); - define_benches!(mod emoji_small, emoji::SMALL, $($name $arg $body)+); - define_benches!(mod emoji_medium, emoji::MEDIUM, $($name $arg $body)+); - define_benches!(mod emoji_large, emoji::LARGE, $($name $arg $body)+); - define_benches!(mod emoji_huge, emoji::HUGE, $($name $arg $body)+); - }; - (mod $mod_name: ident, $input: expr, $($name: ident $arg: ident $body: block)+) => { - mod $mod_name { - use super::*; - $( - #[bench] - fn $name(bencher: &mut Bencher) { - let input = $input; - bencher.bytes = input.len() as u64; - let mut input_s = input.to_string(); - bencher.iter(|| { - let $arg: &str = &black_box(&mut input_s); - black_box($body) - }) - } - )+ - } - }; -} - -define_benches! { - fn case00_libcore(s: &str) { - libcore(s) - } - - fn case01_filter_count_cont_bytes(s: &str) { - filter_count_cont_bytes(s) - } - - fn case02_iter_increment(s: &str) { - iterator_increment(s) - } - - fn case03_manual_char_len(s: &str) { - manual_char_len(s) - } -} - -fn libcore(s: &str) -> usize { - s.chars().count() -} - -#[inline] -fn utf8_is_cont_byte(byte: u8) -> bool { - (byte as i8) < -64 -} - -fn filter_count_cont_bytes(s: &str) -> usize { - s.as_bytes().iter().filter(|&&byte| !utf8_is_cont_byte(byte)).count() -} - -fn iterator_increment(s: &str) -> usize { - let mut c = 0; - for _ in s.chars() { - c += 1; - } - c -} - -fn manual_char_len(s: &str) -> usize { - let s = s.as_bytes(); - let mut c = 0; - let mut i = 0; - let l = s.len(); - while i < l { - let b = s[i]; - if b < 0x80 { - i += 1; - } else if b < 0xe0 { - i += 2; - } else if b < 0xf0 { - i += 3; - } else { - i += 4; - } - c += 1; - } - c -} diff --git a/library/core/benches/str/corpora.rs b/library/core/benches/str/corpora.rs deleted file mode 100644 index b4ac625061d..00000000000 --- a/library/core/benches/str/corpora.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Exposes a number of modules with different kinds of strings. -//! -//! Each module contains `&str` constants named `TINY`, `SMALL`, `MEDIUM`, -//! `LARGE`, and `HUGE`. -//! -//! - The `TINY` string is generally around 8 bytes. -//! - The `SMALL` string is generally around 30-40 bytes. -//! - The `MEDIUM` string is generally around 600-700 bytes. -//! - The `LARGE` string is the `MEDIUM` string repeated 8x, and is around 5kb. -//! - The `HUGE` string is the `LARGE` string repeated 8x (or the `MEDIUM` -//! string repeated 64x), and is around 40kb. -//! -//! Except for `mod emoji` (which is just a bunch of emoji), the strings were -//! pulled from (localizations of) rust-lang.org. - -macro_rules! repeat8 { - ($s:expr) => { - concat!($s, $s, $s, $s, $s, $s, $s, $s) - }; -} - -macro_rules! define_consts { - ($s:literal) => { - pub const MEDIUM: &str = $s; - pub const LARGE: &str = repeat8!($s); - pub const HUGE: &str = repeat8!(repeat8!(repeat8!($s))); - }; -} - -pub mod en { - pub const TINY: &str = "Mary had"; - pub const SMALL: &str = "Mary had a little lamb, Little lamb"; - define_consts! { - "Rust is blazingly fast and memory-efficient: with no runtime or garbage - collector, it can power performance-critical services, run on embedded - devices, and easily integrate with other languages. Rust’s rich type system - and ownership model guarantee memory-safety and thread-safety — enabling you - to eliminate many classes of bugs at compile-time. Rust has great - documentation, a friendly compiler with useful error messages, and top-notch - tooling — an integrated package manager and build tool, smart multi-editor - support with auto-completion and type inspections, an auto-formatter, and - more." - } -} - -pub mod zh { - pub const TINY: &str = "速度惊"; - pub const SMALL: &str = "速度惊人且内存利用率极高"; - define_consts! { - "Rust 速度惊人且内存利用率极高。由于\ - 没有运行时和垃圾回收,它能够胜任对性能要\ - 求特别高的服务,可以在嵌入式设备上运行,\ - 还能轻松和其他语言集成。Rust 丰富的类型\ - 系统和所有权模型保证了内存安全和线程安全,\ - 让您在编译期就能够消除各种各样的错误。\ - Rust 拥有出色的文档、友好的编译器和清晰\ - 的错误提示信息, 还集成了一流的工具——\ - 包管理器和构建工具, 智能地自动补全和类\ - 型检验的多编辑器支持, 以及自动格式化代\ - 码等等。" - } -} - -pub mod ru { - pub const TINY: &str = "Сотни"; - pub const SMALL: &str = "Сотни компаний по"; - define_consts! { - "Сотни компаний по всему миру используют Rust в реальных\ - проектах для быстрых кросс-платформенных решений с\ - ограниченными ресурсами. Такие проекты, как Firefox,\ - Dropbox и Cloudflare, используют Rust. Rust отлично\ - подходит как для стартапов, так и для больших компаний,\ - как для встраиваемых устройств, так и для масштабируемых\ - web-сервисов. Мой самый большой комплимент Rust." - } -} - -pub mod emoji { - pub const TINY: &str = "😀😃"; - pub const SMALL: &str = "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘"; - define_consts! { - "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗☺😚😙🥲😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😶‍🌫️😏😒\ - 🙄😬😮‍💨🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵😵‍💫🤯��🥳🥸😎🤓🧐😕😟🙁☹😮😯😲😳🥺😦😧😨\ - 😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬😈👿💀☠💩🤡👹👺👻👽👾🤖😺😸😹😻😼😽🙀😿😾🙈🙉🙊\ - 💋💌💘💝💖💗💓��💕💟❣💔❤️‍🔥❤️‍🩹❤🧡💛💚💙💜🤎🖤🤍💯💢💥💫💦💨🕳💬👁️‍🗨️🗨🗯💭💤👋\ - 🤚🖐✋🖖👌🤌🤏✌" - } -} diff --git a/library/core/benches/str/debug.rs b/library/core/benches/str/debug.rs deleted file mode 100644 index e41d4fa110a..00000000000 --- a/library/core/benches/str/debug.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! This primarily benchmarks `impl Debug for str`, -//! and it also explicitly tests that we minimizes calls to the underlying `Write`r. -//! While that is an implementation detail and there are no guarantees about it, -//! we should still try to minimize those calls over time rather than regress them. - -use std::fmt::{self, Write}; - -use test::{Bencher, black_box}; - -#[derive(Default)] -struct CountingWriter { - buf: String, - write_calls: usize, -} - -impl Write for CountingWriter { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.buf.push_str(s); - self.write_calls += 1; - Ok(()) - } -} - -fn assert_fmt(s: &str, expected: &str, expected_write_calls: usize) { - let mut w = CountingWriter::default(); - - write!(&mut w, "{s:?}").unwrap(); - assert_eq!(s.len(), 64); - assert_eq!(w.buf, expected); - assert_eq!(w.write_calls, expected_write_calls); -} - -#[bench] -fn ascii_only(b: &mut Bencher) { - let s = "just a bit of ascii text that has no escapes. 64 bytes exactly!!"; - assert_fmt(s, r#""just a bit of ascii text that has no escapes. 64 bytes exactly!!""#, 3); - b.iter(|| { - black_box(format!("{:?}", black_box(s))); - }); -} - -#[bench] -fn ascii_escapes(b: &mut Bencher) { - let s = "some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte"; - assert_fmt( - s, - r#""some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte""#, - 15, - ); - b.iter(|| { - black_box(format!("{:?}", black_box(s))); - }); -} - -#[bench] -fn some_unicode(b: &mut Bencher) { - let s = "egy kis szöveg néhány unicode betűvel. legyen ez is 64 byte."; - assert_fmt(s, r#""egy kis szöveg néhány unicode betűvel. legyen ez is 64 byte.""#, 3); - b.iter(|| { - black_box(format!("{:?}", black_box(s))); - }); -} - -#[bench] -fn mostly_unicode(b: &mut Bencher) { - let s = "предложение из кириллических букв."; - assert_fmt(s, r#""предложение из кириллических букв.""#, 3); - b.iter(|| { - black_box(format!("{:?}", black_box(s))); - }); -} - -#[bench] -fn mixed(b: &mut Bencher) { - let s = "\"❤️\"\n\"hűha ez betű\"\n\"кириллических букв\"."; - assert_fmt(s, r#""\"❤\u{fe0f}\"\n\"hűha ez betű\"\n\"кириллических букв\".""#, 21); - b.iter(|| { - black_box(format!("{:?}", black_box(s))); - }); -} diff --git a/library/core/benches/str/iter.rs b/library/core/benches/str/iter.rs deleted file mode 100644 index d2586cef258..00000000000 --- a/library/core/benches/str/iter.rs +++ /dev/null @@ -1,18 +0,0 @@ -use test::{Bencher, black_box}; - -use super::corpora; - -#[bench] -fn chars_advance_by_1000(b: &mut Bencher) { - b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(1000)); -} - -#[bench] -fn chars_advance_by_0010(b: &mut Bencher) { - b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(10)); -} - -#[bench] -fn chars_advance_by_0001(b: &mut Bencher) { - b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(1)); -} diff --git a/library/core/benches/tuple.rs b/library/core/benches/tuple.rs deleted file mode 100644 index dcda7c641aa..00000000000 --- a/library/core/benches/tuple.rs +++ /dev/null @@ -1,22 +0,0 @@ -use rand::prelude::*; -use test::{Bencher, black_box}; - -#[bench] -fn bench_tuple_comparison(b: &mut Bencher) { - let mut rng = black_box(super::bench_rng()); - - let data = black_box([ - ("core::iter::adapters::Chain", 123_usize), - ("core::iter::adapters::Clone", 456_usize), - ("core::iter::adapters::Copie", 789_usize), - ("core::iter::adapters::Cycle", 123_usize), - ("core::iter::adapters::Flatt", 456_usize), - ("core::iter::adapters::TakeN", 789_usize), - ]); - - b.iter(|| { - let x = data.choose(&mut rng).unwrap(); - let y = data.choose(&mut rng).unwrap(); - [x < y, x <= y, x > y, x >= y] - }); -} diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs deleted file mode 100644 index b88f1821cd7..00000000000 --- a/library/core/tests/alloc.rs +++ /dev/null @@ -1,75 +0,0 @@ -use core::alloc::Layout; -use core::mem::size_of; -use core::ptr::{self, NonNull}; - -#[test] -fn const_unchecked_layout() { - const SIZE: usize = 0x2000; - const ALIGN: usize = 0x1000; - const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) }; - const DANGLING: NonNull = LAYOUT.dangling(); - assert_eq!(LAYOUT.size(), SIZE); - assert_eq!(LAYOUT.align(), ALIGN); - assert_eq!(Some(DANGLING), NonNull::new(ptr::without_provenance_mut(ALIGN))); -} - -#[test] -fn layout_round_up_to_align_edge_cases() { - const MAX_SIZE: usize = isize::MAX as usize; - - for shift in 0..usize::BITS { - let align = 1_usize << shift; - let edge = (MAX_SIZE + 1) - align; - let low = edge.saturating_sub(10); - let high = edge.saturating_add(10); - assert!(Layout::from_size_align(low, align).is_ok()); - assert!(Layout::from_size_align(high, align).is_err()); - for size in low..=high { - assert_eq!( - Layout::from_size_align(size, align).is_ok(), - size.next_multiple_of(align) <= MAX_SIZE, - ); - } - } -} - -#[test] -fn layout_array_edge_cases() { - for_type::(); - for_type::<[i32; 0b10101]>(); - for_type::<[u8; 0b1010101]>(); - - // Make sure ZSTs don't lead to divide-by-zero - assert_eq!(Layout::array::<()>(usize::MAX).unwrap(), Layout::from_size_align(0, 1).unwrap()); - - fn for_type() { - const MAX_SIZE: usize = isize::MAX as usize; - - let edge = (MAX_SIZE + 1) / size_of::(); - let low = edge.saturating_sub(10); - let high = edge.saturating_add(10); - assert!(Layout::array::(low).is_ok()); - assert!(Layout::array::(high).is_err()); - for n in low..=high { - assert_eq!(Layout::array::(n).is_ok(), n * size_of::() <= MAX_SIZE); - } - } -} - -#[test] -fn layout_debug_shows_log2_of_alignment() { - // `Debug` is not stable, but here's what it does right now - let layout = Layout::from_size_align(24576, 8192).unwrap(); - let s = format!("{:?}", layout); - assert_eq!(s, "Layout { size: 24576, align: 8192 (1 << 13) }"); -} - -// Running this normally doesn't do much, but it's also run in Miri, which -// will double-check that these are allowed by the validity invariants. -#[test] -fn layout_accepts_all_valid_alignments() { - for align in 0..usize::BITS { - let layout = Layout::from_size_align(0, 1_usize << align).unwrap(); - assert_eq!(layout.align(), 1_usize << align); - } -} diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs deleted file mode 100644 index 25002617d0b..00000000000 --- a/library/core/tests/any.rs +++ /dev/null @@ -1,149 +0,0 @@ -use core::any::*; - -#[derive(PartialEq, Debug)] -struct Test; - -static TEST: &'static str = "Test"; - -#[test] -fn any_referenced() { - let (a, b, c) = (&5 as &dyn Any, &TEST as &dyn Any, &Test as &dyn Any); - - assert!(a.is::()); - assert!(!b.is::()); - assert!(!c.is::()); - - assert!(!a.is::<&'static str>()); - assert!(b.is::<&'static str>()); - assert!(!c.is::<&'static str>()); - - assert!(!a.is::()); - assert!(!b.is::()); - assert!(c.is::()); -} - -#[test] -fn any_owning() { - let (a, b, c) = ( - Box::new(5_usize) as Box, - Box::new(TEST) as Box, - Box::new(Test) as Box, - ); - - assert!(a.is::()); - assert!(!b.is::()); - assert!(!c.is::()); - - assert!(!a.is::<&'static str>()); - assert!(b.is::<&'static str>()); - assert!(!c.is::<&'static str>()); - - assert!(!a.is::()); - assert!(!b.is::()); - assert!(c.is::()); -} - -#[test] -fn any_downcast_ref() { - let a = &5_usize as &dyn Any; - - match a.downcast_ref::() { - Some(&5) => {} - x => panic!("Unexpected value {x:?}"), - } - - match a.downcast_ref::() { - None => {} - x => panic!("Unexpected value {x:?}"), - } -} - -#[test] -fn any_downcast_mut() { - let mut a = 5_usize; - let mut b: Box<_> = Box::new(7_usize); - - let a_r = &mut a as &mut dyn Any; - let tmp: &mut usize = &mut *b; - let b_r = tmp as &mut dyn Any; - - match a_r.downcast_mut::() { - Some(x) => { - assert_eq!(*x, 5); - *x = 612; - } - x => panic!("Unexpected value {x:?}"), - } - - match b_r.downcast_mut::() { - Some(x) => { - assert_eq!(*x, 7); - *x = 413; - } - x => panic!("Unexpected value {x:?}"), - } - - match a_r.downcast_mut::() { - None => (), - x => panic!("Unexpected value {x:?}"), - } - - match b_r.downcast_mut::() { - None => (), - x => panic!("Unexpected value {x:?}"), - } - - match a_r.downcast_mut::() { - Some(&mut 612) => {} - x => panic!("Unexpected value {x:?}"), - } - - match b_r.downcast_mut::() { - Some(&mut 413) => {} - x => panic!("Unexpected value {x:?}"), - } -} - -#[test] -fn any_fixed_vec() { - let test = [0_usize; 8]; - let test = &test as &dyn Any; - assert!(test.is::<[usize; 8]>()); - assert!(!test.is::<[usize; 10]>()); -} - -#[test] -fn any_unsized() { - fn is_any() {} - is_any::<[i32]>(); -} - -#[test] -fn distinct_type_names() { - // https://github.com/rust-lang/rust/issues/84666 - - struct Velocity(#[allow(dead_code)] f32, #[allow(dead_code)] f32); - - fn type_name_of_val(_: T) -> &'static str { - type_name::() - } - - assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),); -} - -#[test] -fn dyn_type_name() { - trait Foo { - type Bar; - } - - assert_eq!( - "dyn core::ops::function::Fn(i32, i32) -> i32", - std::any::type_name:: i32>() - ); - assert_eq!( - "dyn coretests::any::dyn_type_name::Foo \ - + core::marker::Send + core::marker::Sync", - std::any::type_name:: + Send + Sync>() - ); -} diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs deleted file mode 100644 index b6d18f1ec38..00000000000 --- a/library/core/tests/array.rs +++ /dev/null @@ -1,719 +0,0 @@ -use core::num::NonZero; -use core::sync::atomic::{AtomicUsize, Ordering}; -use core::{array, assert_eq}; - -#[test] -fn array_from_ref() { - let value: String = "Hello World!".into(); - let arr: &[String; 1] = array::from_ref(&value); - assert_eq!(&[value.clone()], arr); - - const VALUE: &&str = &"Hello World!"; - const ARR: &[&str; 1] = array::from_ref(VALUE); - assert_eq!(&[*VALUE], ARR); - assert!(core::ptr::eq(VALUE, &ARR[0])); -} - -#[test] -fn array_from_mut() { - let mut value: String = "Hello World".into(); - let arr: &mut [String; 1] = array::from_mut(&mut value); - arr[0].push_str("!"); - assert_eq!(&value, "Hello World!"); -} - -#[test] -fn array_try_from() { - macro_rules! test { - ($($N:expr)+) => { - $({ - type Array = [u8; $N]; - let mut array: Array = [0; $N]; - let slice: &[u8] = &array[..]; - - let result = <&Array>::try_from(slice); - assert_eq!(&array, result.unwrap()); - - let result = ::try_from(slice); - assert_eq!(&array, &result.unwrap()); - - let mut_slice: &mut [u8] = &mut array[..]; - let result = <&mut Array>::try_from(mut_slice); - assert_eq!(&[0; $N], result.unwrap()); - - let mut_slice: &mut [u8] = &mut array[..]; - let result = ::try_from(mut_slice); - assert_eq!(&array, &result.unwrap()); - })+ - } - } - test! { - 0 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 27 28 29 - 30 31 32 - } -} - -#[test] -fn iterator_collect() { - let arr = [0, 1, 2, 5, 9]; - let v: Vec<_> = IntoIterator::into_iter(arr.clone()).collect(); - assert_eq!(&arr[..], &v[..]); -} - -#[test] -fn iterator_rev_collect() { - let arr = [0, 1, 2, 5, 9]; - let v: Vec<_> = IntoIterator::into_iter(arr.clone()).rev().collect(); - assert_eq!(&v[..], &[9, 5, 2, 1, 0]); -} - -#[test] -fn iterator_nth() { - let v = [0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(IntoIterator::into_iter(v.clone()).nth(i).unwrap(), v[i]); - } - assert_eq!(IntoIterator::into_iter(v.clone()).nth(v.len()), None); - - let mut iter = IntoIterator::into_iter(v); - assert_eq!(iter.nth(2).unwrap(), v[2]); - assert_eq!(iter.nth(1).unwrap(), v[4]); -} - -#[test] -fn iterator_last() { - let v = [0, 1, 2, 3, 4]; - assert_eq!(IntoIterator::into_iter(v).last().unwrap(), 4); - assert_eq!(IntoIterator::into_iter([0]).last().unwrap(), 0); - - let mut it = IntoIterator::into_iter([0, 9, 2, 4]); - assert_eq!(it.next_back(), Some(4)); - assert_eq!(it.last(), Some(2)); -} - -#[test] -fn iterator_clone() { - let mut it = IntoIterator::into_iter([0, 2, 4, 6, 8]); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next_back(), Some(8)); - let mut clone = it.clone(); - assert_eq!(it.next_back(), Some(6)); - assert_eq!(clone.next_back(), Some(6)); - assert_eq!(it.next_back(), Some(4)); - assert_eq!(clone.next_back(), Some(4)); - assert_eq!(it.next(), Some(2)); - assert_eq!(clone.next(), Some(2)); -} - -#[test] -fn iterator_fused() { - let mut it = IntoIterator::into_iter([0, 9, 2]); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next(), Some(9)); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.next(), None); - assert_eq!(it.next(), None); - assert_eq!(it.next(), None); - assert_eq!(it.next(), None); - assert_eq!(it.next(), None); -} - -#[test] -fn iterator_len() { - let mut it = IntoIterator::into_iter([0, 1, 2, 5, 9]); - assert_eq!(it.size_hint(), (5, Some(5))); - assert_eq!(it.len(), 5); - assert_eq!(it.is_empty(), false); - - assert_eq!(it.next(), Some(0)); - assert_eq!(it.size_hint(), (4, Some(4))); - assert_eq!(it.len(), 4); - assert_eq!(it.is_empty(), false); - - assert_eq!(it.next_back(), Some(9)); - assert_eq!(it.size_hint(), (3, Some(3))); - assert_eq!(it.len(), 3); - assert_eq!(it.is_empty(), false); - - // Empty - let it = IntoIterator::into_iter([] as [String; 0]); - assert_eq!(it.size_hint(), (0, Some(0))); - assert_eq!(it.len(), 0); - assert_eq!(it.is_empty(), true); -} - -#[test] -fn iterator_count() { - let v = [0, 1, 2, 3, 4]; - assert_eq!(IntoIterator::into_iter(v.clone()).count(), 5); - - let mut iter2 = IntoIterator::into_iter(v); - iter2.next(); - iter2.next(); - assert_eq!(iter2.count(), 3); -} - -#[test] -fn iterator_flat_map() { - assert!((0..5).flat_map(|i| IntoIterator::into_iter([2 * i, 2 * i + 1])).eq(0..10)); -} - -#[test] -fn iterator_debug() { - let arr = [0, 1, 2, 5, 9]; - assert_eq!(format!("{:?}", IntoIterator::into_iter(arr)), "IntoIter([0, 1, 2, 5, 9])",); -} - -#[test] -fn iterator_drops() { - use core::cell::Cell; - - // This test makes sure the correct number of elements are dropped. The `R` - // type is just a reference to a `Cell` that is incremented when an `R` is - // dropped. - - #[derive(Clone)] - struct Foo<'a>(&'a Cell); - - impl Drop for Foo<'_> { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } - } - - fn five(i: &Cell) -> [Foo<'_>; 5] { - // This is somewhat verbose because `Foo` does not implement `Copy` - // since it implements `Drop`. Consequently, we cannot write - // `[Foo(i); 5]`. - [Foo(i), Foo(i), Foo(i), Foo(i), Foo(i)] - } - - // Simple: drop new iterator. - let i = Cell::new(0); - { - IntoIterator::into_iter(five(&i)); - } - assert_eq!(i.get(), 5); - - // Call `next()` once. - let i = Cell::new(0); - { - let mut iter = IntoIterator::into_iter(five(&i)); - let _x = iter.next(); - assert_eq!(i.get(), 0); - assert_eq!(iter.count(), 4); - assert_eq!(i.get(), 4); - } - assert_eq!(i.get(), 5); - - // Check `clone` and calling `next`/`next_back`. - let i = Cell::new(0); - { - let mut iter = IntoIterator::into_iter(five(&i)); - iter.next(); - assert_eq!(i.get(), 1); - iter.next_back(); - assert_eq!(i.get(), 2); - - let mut clone = iter.clone(); - assert_eq!(i.get(), 2); - - iter.next(); - assert_eq!(i.get(), 3); - - clone.next(); - assert_eq!(i.get(), 4); - - assert_eq!(clone.count(), 2); - assert_eq!(i.get(), 6); - } - assert_eq!(i.get(), 8); - - // Check via `nth`. - let i = Cell::new(0); - { - let mut iter = IntoIterator::into_iter(five(&i)); - let _x = iter.nth(2); - assert_eq!(i.get(), 2); - let _y = iter.last(); - assert_eq!(i.get(), 3); - } - assert_eq!(i.get(), 5); - - // Check every element. - let i = Cell::new(0); - for (index, _x) in IntoIterator::into_iter(five(&i)).enumerate() { - assert_eq!(i.get(), index); - } - assert_eq!(i.get(), 5); - - let i = Cell::new(0); - for (index, _x) in IntoIterator::into_iter(five(&i)).rev().enumerate() { - assert_eq!(i.get(), index); - } - assert_eq!(i.get(), 5); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn array_default_impl_avoids_leaks_on_panic() { - use core::sync::atomic::AtomicUsize; - use core::sync::atomic::Ordering::Relaxed; - static COUNTER: AtomicUsize = AtomicUsize::new(0); - #[derive(Debug)] - struct Bomb(#[allow(dead_code)] usize); - - impl Default for Bomb { - fn default() -> Bomb { - if COUNTER.load(Relaxed) == 3 { - panic!("bomb limit exceeded"); - } - - COUNTER.fetch_add(1, Relaxed); - Bomb(COUNTER.load(Relaxed)) - } - } - - impl Drop for Bomb { - fn drop(&mut self) { - COUNTER.fetch_sub(1, Relaxed); - } - } - - let res = std::panic::catch_unwind(|| <[Bomb; 5]>::default()); - let panic_msg = match res { - Ok(_) => unreachable!(), - Err(p) => p.downcast::<&'static str>().unwrap(), - }; - assert_eq!(*panic_msg, "bomb limit exceeded"); - // check that all bombs are successfully dropped - assert_eq!(COUNTER.load(Relaxed), 0); -} - -#[test] -fn empty_array_is_always_default() { - struct DoesNotImplDefault; - - let _arr = <[DoesNotImplDefault; 0]>::default(); -} - -#[test] -fn array_map() { - let a = [1, 2, 3]; - let b = a.map(|v| v + 1); - assert_eq!(b, [2, 3, 4]); - - let a = [1u8, 2, 3]; - let b = a.map(|v| v as u64); - assert_eq!(b, [1, 2, 3]); -} - -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn array_map_drop_safety() { - static DROPPED: AtomicUsize = AtomicUsize::new(0); - struct DropCounter; - impl Drop for DropCounter { - fn drop(&mut self) { - DROPPED.fetch_add(1, Ordering::SeqCst); - } - } - - let num_to_create = 5; - let success = std::panic::catch_unwind(|| { - let items = [0; 10]; - let mut nth = 0; - items.map(|_| { - assert!(nth < num_to_create); - nth += 1; - DropCounter - }); - }); - assert!(success.is_err()); - assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create); -} - -#[test] -fn cell_allows_array_cycle() { - use core::cell::Cell; - - #[derive(Debug)] - struct B<'a> { - a: [Cell>>; 2], - } - - impl<'a> B<'a> { - fn new() -> B<'a> { - B { a: [Cell::new(None), Cell::new(None)] } - } - } - - let b1 = B::new(); - let b2 = B::new(); - let b3 = B::new(); - - b1.a[0].set(Some(&b2)); - b1.a[1].set(Some(&b3)); - - b2.a[0].set(Some(&b2)); - b2.a[1].set(Some(&b3)); - - b3.a[0].set(Some(&b1)); - b3.a[1].set(Some(&b2)); -} - -#[test] -fn array_from_fn() { - let array = core::array::from_fn(|idx| idx); - assert_eq!(array, [0, 1, 2, 3, 4]); -} - -#[test] -fn array_try_from_fn() { - #[derive(Debug, PartialEq)] - enum SomeError { - Foo, - } - - let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i)); - assert_eq!(array, Ok([0, 1, 2, 3, 4])); - - let another_array = core::array::try_from_fn::, 2, _>(|_| Err(SomeError::Foo)); - assert_eq!(another_array, Err(SomeError::Foo)); -} - -#[cfg(not(panic = "abort"))] -#[test] -fn array_try_from_fn_drops_inserted_elements_on_err() { - static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); - - struct CountDrop; - impl Drop for CountDrop { - fn drop(&mut self) { - DROP_COUNTER.fetch_add(1, Ordering::SeqCst); - } - } - - let _ = catch_unwind_silent(move || { - let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| { - if idx == 2 { - return Err(()); - } - Ok(CountDrop) - }); - }); - - assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2); -} - -#[cfg(not(panic = "abort"))] -#[test] -fn array_try_from_fn_drops_inserted_elements_on_panic() { - static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); - - struct CountDrop; - impl Drop for CountDrop { - fn drop(&mut self) { - DROP_COUNTER.fetch_add(1, Ordering::SeqCst); - } - } - - let _ = catch_unwind_silent(move || { - let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| { - if idx == 2 { - panic!("peek a boo"); - } - Ok(CountDrop) - }); - }); - - assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2); -} - -#[cfg(not(panic = "abort"))] -// https://stackoverflow.com/a/59211505 -fn catch_unwind_silent(f: F) -> std::thread::Result -where - F: FnOnce() -> R + core::panic::UnwindSafe, -{ - let prev_hook = std::panic::take_hook(); - std::panic::set_hook(Box::new(|_| {})); - let result = std::panic::catch_unwind(f); - std::panic::set_hook(prev_hook); - result -} - -#[test] -fn array_split_array_mut() { - let mut v = [1, 2, 3, 4, 5, 6]; - - { - let (left, right) = v.split_array_mut::<0>(); - assert_eq!(left, &mut []); - assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); - } - - { - let (left, right) = v.split_array_mut::<6>(); - assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); - assert_eq!(right, &mut []); - } -} - -#[test] -fn array_rsplit_array_mut() { - let mut v = [1, 2, 3, 4, 5, 6]; - - { - let (left, right) = v.rsplit_array_mut::<0>(); - assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); - assert_eq!(right, &mut []); - } - - { - let (left, right) = v.rsplit_array_mut::<6>(); - assert_eq!(left, &mut []); - assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); - } -} - -#[should_panic] -#[test] -fn array_split_array_ref_out_of_bounds() { - let v = [1, 2, 3, 4, 5, 6]; - - v.split_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn array_split_array_mut_out_of_bounds() { - let mut v = [1, 2, 3, 4, 5, 6]; - - v.split_array_mut::<7>(); -} - -#[should_panic] -#[test] -fn array_rsplit_array_ref_out_of_bounds() { - let v = [1, 2, 3, 4, 5, 6]; - - v.rsplit_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn array_rsplit_array_mut_out_of_bounds() { - let mut v = [1, 2, 3, 4, 5, 6]; - - v.rsplit_array_mut::<7>(); -} - -#[test] -fn array_intoiter_advance_by() { - use std::cell::Cell; - struct DropCounter<'a>(usize, &'a Cell); - impl Drop for DropCounter<'_> { - fn drop(&mut self) { - let x = self.1.get(); - self.1.set(x + 1); - } - } - - let counter = Cell::new(0); - let a: [_; 100] = std::array::from_fn(|i| DropCounter(i, &counter)); - let mut it = IntoIterator::into_iter(a); - - let r = it.advance_by(1); - assert_eq!(r, Ok(())); - assert_eq!(it.len(), 99); - assert_eq!(counter.get(), 1); - - let r = it.advance_by(0); - assert_eq!(r, Ok(())); - assert_eq!(it.len(), 99); - assert_eq!(counter.get(), 1); - - let r = it.advance_by(11); - assert_eq!(r, Ok(())); - assert_eq!(it.len(), 88); - assert_eq!(counter.get(), 12); - - let x = it.next(); - assert_eq!(x.as_ref().map(|x| x.0), Some(12)); - assert_eq!(it.len(), 87); - assert_eq!(counter.get(), 12); - drop(x); - assert_eq!(counter.get(), 13); - - let r = it.advance_by(123456); - assert_eq!(r, Err(NonZero::new(123456 - 87).unwrap())); - assert_eq!(it.len(), 0); - assert_eq!(counter.get(), 100); - - let r = it.advance_by(0); - assert_eq!(r, Ok(())); - assert_eq!(it.len(), 0); - assert_eq!(counter.get(), 100); - - let r = it.advance_by(10); - assert_eq!(r, Err(NonZero::new(10).unwrap())); - assert_eq!(it.len(), 0); - assert_eq!(counter.get(), 100); -} - -#[test] -fn array_intoiter_advance_back_by() { - use std::cell::Cell; - struct DropCounter<'a>(usize, &'a Cell); - impl Drop for DropCounter<'_> { - fn drop(&mut self) { - let x = self.1.get(); - self.1.set(x + 1); - } - } - - let counter = Cell::new(0); - let a: [_; 100] = std::array::from_fn(|i| DropCounter(i, &counter)); - let mut it = IntoIterator::into_iter(a); - - let r = it.advance_back_by(1); - assert_eq!(r, Ok(())); - assert_eq!(it.len(), 99); - assert_eq!(counter.get(), 1); - - let r = it.advance_back_by(0); - assert_eq!(r, Ok(())); - assert_eq!(it.len(), 99); - assert_eq!(counter.get(), 1); - - let r = it.advance_back_by(11); - assert_eq!(r, Ok(())); - assert_eq!(it.len(), 88); - assert_eq!(counter.get(), 12); - - let x = it.next_back(); - assert_eq!(x.as_ref().map(|x| x.0), Some(87)); - assert_eq!(it.len(), 87); - assert_eq!(counter.get(), 12); - drop(x); - assert_eq!(counter.get(), 13); - - let r = it.advance_back_by(123456); - assert_eq!(r, Err(NonZero::new(123456 - 87).unwrap())); - assert_eq!(it.len(), 0); - assert_eq!(counter.get(), 100); - - let r = it.advance_back_by(0); - assert_eq!(r, Ok(())); - assert_eq!(it.len(), 0); - assert_eq!(counter.get(), 100); - - let r = it.advance_back_by(10); - assert_eq!(r, Err(NonZero::new(10).unwrap())); - assert_eq!(it.len(), 0); - assert_eq!(counter.get(), 100); -} - -#[test] -fn array_mixed_equality_integers() { - let array3: [i32; 3] = [1, 2, 3]; - let array3b: [i32; 3] = [3, 2, 1]; - let array4: [i32; 4] = [1, 2, 3, 4]; - - let slice3: &[i32] = &{ array3 }; - let slice3b: &[i32] = &{ array3b }; - let slice4: &[i32] = &{ array4 }; - assert!(array3 == slice3); - assert!(array3 != slice3b); - assert!(array3 != slice4); - assert!(slice3 == array3); - assert!(slice3b != array3); - assert!(slice4 != array3); - - let mut3: &mut [i32] = &mut { array3 }; - let mut3b: &mut [i32] = &mut { array3b }; - let mut4: &mut [i32] = &mut { array4 }; - assert!(array3 == mut3); - assert!(array3 != mut3b); - assert!(array3 != mut4); - assert!(mut3 == array3); - assert!(mut3b != array3); - assert!(mut4 != array3); -} - -#[test] -fn array_mixed_equality_nans() { - let array3: [f32; 3] = [1.0, std::f32::NAN, 3.0]; - - let slice3: &[f32] = &{ array3 }; - assert!(!(array3 == slice3)); - assert!(array3 != slice3); - assert!(!(slice3 == array3)); - assert!(slice3 != array3); - - let mut3: &mut [f32] = &mut { array3 }; - assert!(!(array3 == mut3)); - assert!(array3 != mut3); - assert!(!(mut3 == array3)); - assert!(mut3 != array3); -} - -#[test] -fn array_into_iter_fold() { - // Strings to help Miri catch if we double-free or something - let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()]; - let mut s = "s".to_string(); - a.into_iter().for_each(|b| s += &b); - assert_eq!(s, "sAaBbCc"); - - let a = [1, 2, 3, 4, 5, 6]; - let mut it = a.into_iter(); - assert_eq!(it.advance_by(1), Ok(())); - assert_eq!(it.advance_back_by(2), Ok(())); - let s = it.fold(10, |a, b| 10 * a + b); - assert_eq!(s, 10234); -} - -#[test] -fn array_into_iter_rfold() { - // Strings to help Miri catch if we double-free or something - let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()]; - let mut s = "s".to_string(); - a.into_iter().rev().for_each(|b| s += &b); - assert_eq!(s, "sCcBbAa"); - - let a = [1, 2, 3, 4, 5, 6]; - let mut it = a.into_iter(); - assert_eq!(it.advance_by(1), Ok(())); - assert_eq!(it.advance_back_by(2), Ok(())); - let s = it.rfold(10, |a, b| 10 * a + b); - assert_eq!(s, 10432); -} - -#[cfg(not(panic = "abort"))] -#[test] -fn array_map_drops_unmapped_elements_on_panic() { - struct DropCounter<'a>(usize, &'a AtomicUsize); - impl Drop for DropCounter<'_> { - fn drop(&mut self) { - self.1.fetch_add(1, Ordering::SeqCst); - } - } - - const MAX: usize = 11; - for panic_after in 0..MAX { - let counter = AtomicUsize::new(0); - let a = array::from_fn::<_, 11, _>(|i| DropCounter(i, &counter)); - let success = std::panic::catch_unwind(|| { - let _ = a.map(|x| { - assert!(x.0 < panic_after); - assert_eq!(counter.load(Ordering::SeqCst), x.0); - }); - }); - assert!(success.is_err()); - assert_eq!(counter.load(Ordering::SeqCst), MAX); - } -} diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs deleted file mode 100644 index ce09ee507f1..00000000000 --- a/library/core/tests/ascii.rs +++ /dev/null @@ -1,507 +0,0 @@ -use core::char::from_u32; - -#[test] -fn test_is_ascii() { - assert!(b"".is_ascii()); - assert!(b"banana\0\x7F".is_ascii()); - assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); - assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); - assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); - assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); - - assert!("".is_ascii()); - assert!("banana\0\u{7F}".is_ascii()); - assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); -} - -#[test] -fn test_to_ascii_uppercase() { - assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); - assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); - - for i in 0..501 { - let upper = - if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } else { i }; - assert_eq!( - (from_u32(i).unwrap()).to_string().to_ascii_uppercase(), - (from_u32(upper).unwrap()).to_string() - ); - } -} - -#[test] -fn test_to_ascii_lowercase() { - assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); - // Dotted capital I, Kelvin sign, Sharp S. - assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); - - for i in 0..501 { - let lower = - if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i }; - assert_eq!( - (from_u32(i).unwrap()).to_string().to_ascii_lowercase(), - (from_u32(lower).unwrap()).to_string() - ); - } -} - -#[test] -fn test_make_ascii_lower_case() { - macro_rules! test { - ($from: expr, $to: expr) => {{ - let mut x = $from; - x.make_ascii_lowercase(); - assert_eq!(x, $to); - }}; - } - test!(b'A', b'a'); - test!(b'a', b'a'); - test!(b'!', b'!'); - test!('A', 'a'); - test!('À', 'À'); - test!('a', 'a'); - test!('!', '!'); - test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); - test!("HİKß".to_string(), "hİKß"); -} - -#[test] -fn test_make_ascii_upper_case() { - macro_rules! test { - ($from: expr, $to: expr) => {{ - let mut x = $from; - x.make_ascii_uppercase(); - assert_eq!(x, $to); - }}; - } - test!(b'a', b'A'); - test!(b'A', b'A'); - test!(b'!', b'!'); - test!('a', 'A'); - test!('à', 'à'); - test!('A', 'A'); - test!('!', '!'); - test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); - test!("hıKß".to_string(), "HıKß"); - - let mut x = "Hello".to_string(); - x[..3].make_ascii_uppercase(); // Test IndexMut on String. - assert_eq!(x, "HELlo") -} - -#[test] -fn test_eq_ignore_ascii_case() { - assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); - assert!(!"Ürl".eq_ignore_ascii_case("ürl")); - // Dotted capital I, Kelvin sign, Sharp S. - assert!("HİKß".eq_ignore_ascii_case("hİKß")); - assert!(!"İ".eq_ignore_ascii_case("i")); - assert!(!"K".eq_ignore_ascii_case("k")); - assert!(!"ß".eq_ignore_ascii_case("s")); - - for i in 0..501 { - let lower = - if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i }; - assert!( - (from_u32(i).unwrap()) - .to_string() - .eq_ignore_ascii_case(&from_u32(lower).unwrap().to_string()) - ); - } -} - -#[test] -fn inference_works() { - let x = "a".to_string(); - let _ = x.eq_ignore_ascii_case("A"); -} - -// Shorthands used by the is_ascii_* tests. -macro_rules! assert_all { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if !b.$what() { - panic!("expected {}({}) but it isn't", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if !b.$what() { - panic!("expected {}(0x{:02x})) but it isn't", - stringify!($what), b); - } - } - )+ - }}; - ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) -} -macro_rules! assert_none { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if b.$what() { - panic!("expected not-{}({}) but it is", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if b.$what() { - panic!("expected not-{}(0x{:02x})) but it is", - stringify!($what), b); - } - } - )+ - }}; - ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) -} - -#[test] -fn test_is_ascii_alphabetic() { - assert_all!( - is_ascii_alphabetic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!( - is_ascii_alphabetic, - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_uppercase() { - assert_all!(is_ascii_uppercase, "", "ABCDEFGHIJKLMNOQPRSTUVWXYZ",); - assert_none!( - is_ascii_uppercase, - "abcdefghijklmnopqrstuvwxyz", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_lowercase() { - assert_all!(is_ascii_lowercase, "abcdefghijklmnopqrstuvwxyz",); - assert_none!( - is_ascii_lowercase, - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_alphanumeric() { - assert_all!( - is_ascii_alphanumeric, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - ); - assert_none!( - is_ascii_alphanumeric, - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_digit() { - assert_all!(is_ascii_digit, "", "0123456789",); - assert_none!( - is_ascii_digit, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_octdigit() { - assert_all!(is_ascii_octdigit, "", "01234567"); - assert_none!( - is_ascii_octdigit, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_hexdigit() { - assert_all!(is_ascii_hexdigit, "", "0123456789", "abcdefABCDEF",); - assert_none!( - is_ascii_hexdigit, - "ghijklmnopqrstuvwxyz", - "GHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_punctuation() { - assert_all!(is_ascii_punctuation, "", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",); - assert_none!( - is_ascii_punctuation, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_graphic() { - assert_all!( - is_ascii_graphic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!( - is_ascii_graphic, - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_whitespace() { - assert_all!(is_ascii_whitespace, "", " \t\n\x0c\r",); - assert_none!( - is_ascii_whitespace, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x0b\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); -} - -#[test] -fn test_is_ascii_control() { - assert_all!( - is_ascii_control, - "", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - assert_none!( - is_ascii_control, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " ", - ); -} - -// `is_ascii` does a good amount of pointer manipulation and has -// alignment-dependent computation. This is all sanity-checked via -// `debug_assert!`s, so we test various sizes/alignments thoroughly versus an -// "obviously correct" baseline function. -#[test] -fn test_is_ascii_align_size_thoroughly() { - // The "obviously-correct" baseline mentioned above. - fn is_ascii_baseline(s: &[u8]) -> bool { - s.iter().all(|b| b.is_ascii()) - } - - // Helper to repeat `l` copies of `b0` followed by `l` copies of `b1`. - fn repeat_concat(b0: u8, b1: u8, l: usize) -> Vec { - use core::iter::repeat; - repeat(b0).take(l).chain(repeat(b1).take(l)).collect() - } - - // Miri is too slow - let iter = if cfg!(miri) { 0..20 } else { 0..100 }; - - for i in iter { - #[cfg(not(miri))] - let cases = &[ - b"a".repeat(i), - b"\0".repeat(i), - b"\x7f".repeat(i), - b"\x80".repeat(i), - b"\xff".repeat(i), - repeat_concat(b'a', 0x80u8, i), - repeat_concat(0x80u8, b'a', i), - ]; - - #[cfg(miri)] - let cases = &[b"a".repeat(i), b"\x80".repeat(i), repeat_concat(b'a', 0x80u8, i)]; - - for case in cases { - for pos in 0..=case.len() { - // Potentially misaligned head - let prefix = &case[pos..]; - assert_eq!(is_ascii_baseline(prefix), prefix.is_ascii(),); - - // Potentially misaligned tail - let suffix = &case[..case.len() - pos]; - - assert_eq!(is_ascii_baseline(suffix), suffix.is_ascii(),); - - // Both head and tail are potentially misaligned - let mid = &case[(pos / 2)..(case.len() - (pos / 2))]; - assert_eq!(is_ascii_baseline(mid), mid.is_ascii(),); - } - } - } -} - -#[test] -fn ascii_const() { - // test that the `is_ascii` methods of `char` and `u8` are usable in a const context - - const CHAR_IS_ASCII: bool = 'a'.is_ascii(); - assert!(CHAR_IS_ASCII); - - const BYTE_IS_ASCII: bool = 97u8.is_ascii(); - assert!(BYTE_IS_ASCII); -} - -#[test] -fn ascii_ctype_const() { - macro_rules! suite { - ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { - $( - mod $fn { - const CHAR_A_LOWER: bool = 'a'.$fn(); - const CHAR_A_UPPER: bool = 'A'.$fn(); - const CHAR_NINE: bool = '9'.$fn(); - const CHAR_DOT: bool = '.'.$fn(); - const CHAR_SPACE: bool = ' '.$fn(); - - const U8_A_LOWER: bool = b'a'.$fn(); - const U8_A_UPPER: bool = b'A'.$fn(); - const U8_NINE: bool = b'9'.$fn(); - const U8_DOT: bool = b'.'.$fn(); - const U8_SPACE: bool = b' '.$fn(); - - pub fn run() { - assert_eq!(CHAR_A_LOWER, $a); - assert_eq!(CHAR_A_UPPER, $A); - assert_eq!(CHAR_NINE, $nine); - assert_eq!(CHAR_DOT, $dot); - assert_eq!(CHAR_SPACE, $space); - - assert_eq!(U8_A_LOWER, $a); - assert_eq!(U8_A_UPPER, $A); - assert_eq!(U8_NINE, $nine); - assert_eq!(U8_DOT, $dot); - assert_eq!(U8_SPACE, $space); - } - } - )* - - $( $fn::run(); )* - } - } - - suite! { - // 'a' 'A' '9' '.' ' ' - is_ascii_alphabetic => [true, true, false, false, false]; - is_ascii_uppercase => [false, true, false, false, false]; - is_ascii_lowercase => [true, false, false, false, false]; - is_ascii_alphanumeric => [true, true, true, false, false]; - is_ascii_digit => [false, false, true, false, false]; - is_ascii_octdigit => [false, false, false, false, false]; - is_ascii_hexdigit => [true, true, true, false, false]; - is_ascii_punctuation => [false, false, false, true, false]; - is_ascii_graphic => [true, true, true, true, false]; - is_ascii_whitespace => [false, false, false, false, true]; - is_ascii_control => [false, false, false, false, false]; - } -} - -#[test] -fn test_escape_ascii() { - let mut buf = [0u8; 0x1F + 7]; // 0..=0x1F plus two quotes, slash, \x7F, \x80, \xFF - for idx in 0..=0x1F { - buf[idx] = idx as u8; - } - buf[0x20] = b'\''; - buf[0x21] = b'"'; - buf[0x22] = b'\\'; - buf[0x23] = 0x7F; - buf[0x24] = 0x80; - buf[0x25] = 0xff; - assert_eq!( - buf.escape_ascii().to_string(), - r#"\x00\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\'\"\\\x7f\x80\xff"# - ); -} - -#[test] -fn test_escape_ascii_iter() { - let mut it = b"\0fastpath\xffremainder\xff".escape_ascii(); - let _ = it.advance_by(4); - let _ = it.advance_back_by(4); - assert_eq!(it.to_string(), r#"fastpath\xffremainder"#); -} diff --git a/library/core/tests/ascii_char.rs b/library/core/tests/ascii_char.rs deleted file mode 100644 index 75b5fd4b9e6..00000000000 --- a/library/core/tests/ascii_char.rs +++ /dev/null @@ -1,28 +0,0 @@ -use core::ascii::Char; -use core::fmt::Write; - -/// Tests Display implementation for ascii::Char. -#[test] -fn test_display() { - let want = (0..128u8).map(|b| b as char).collect::(); - let mut got = String::with_capacity(128); - for byte in 0..128 { - write!(&mut got, "{}", Char::from_u8(byte).unwrap()).unwrap(); - } - assert_eq!(want, got); -} - -/// Tests Debug implementation for ascii::Char. -#[test] -fn test_debug_control() { - for byte in 0..128u8 { - let mut want = format!("{:?}", byte as char); - // `char` uses `'\u{#}'` representation where ascii::char uses `'\x##'`. - // Transform former into the latter. - if let Some(rest) = want.strip_prefix("'\\u{") { - want = format!("'\\x{:0>2}'", rest.strip_suffix("}'").unwrap()); - } - let chr = core::ascii::Char::from_u8(byte).unwrap(); - assert_eq!(want, format!("{chr:?}"), "byte: {byte}"); - } -} diff --git a/library/core/tests/asserting.rs b/library/core/tests/asserting.rs deleted file mode 100644 index 1d9670886eb..00000000000 --- a/library/core/tests/asserting.rs +++ /dev/null @@ -1,37 +0,0 @@ -use core::asserting::{Capture, TryCaptureGeneric, TryCapturePrintable, Wrapper}; - -macro_rules! test { - ($test_name:ident, $elem:expr, $captured_elem:expr, $output:literal) => { - #[test] - fn $test_name() { - let elem = $elem; - let mut capture = Capture::new(); - assert!(capture.elem == None); - (&Wrapper(&elem)).try_capture(&mut capture); - assert!(capture.elem == $captured_elem); - assert_eq!(format!("{:?}", capture), $output); - } - }; -} - -#[derive(Debug, PartialEq)] -struct NoCopy; - -#[derive(PartialEq)] -struct NoCopyNoDebug; - -#[derive(Clone, Copy, PartialEq)] -struct NoDebug; - -test!( - capture_with_non_copyable_and_non_debuggable_elem_has_correct_params, - NoCopyNoDebug, - None, - "N/A" -); - -test!(capture_with_non_copyable_elem_has_correct_params, NoCopy, None, "N/A"); - -test!(capture_with_non_debuggable_elem_has_correct_params, NoDebug, None, "N/A"); - -test!(capture_with_copyable_and_debuggable_elem_has_correct_params, 1i32, Some(1i32), "1"); diff --git a/library/core/tests/async_iter/mod.rs b/library/core/tests/async_iter/mod.rs deleted file mode 100644 index 4f425d7286d..00000000000 --- a/library/core/tests/async_iter/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -use core::async_iter::{self, AsyncIterator, IntoAsyncIterator}; -use core::pin::pin; -use core::task::Poll; - -#[test] -fn into_async_iter() { - let async_iter = async_iter::from_iter(0..3); - let mut async_iter = pin!(async_iter.into_async_iter()); - - let mut cx = &mut core::task::Context::from_waker(core::task::Waker::noop()); - - assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(0))); - assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(1))); - assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(2))); - assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(None)); -} diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs deleted file mode 100644 index 0ffba538b20..00000000000 --- a/library/core/tests/atomic.rs +++ /dev/null @@ -1,318 +0,0 @@ -use core::sync::atomic::Ordering::SeqCst; -use core::sync::atomic::*; - -#[test] -fn bool_() { - let a = AtomicBool::new(false); - assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false)); - assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Err(true)); - - a.store(false, SeqCst); - assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false)); -} - -#[test] -fn bool_and() { - let a = AtomicBool::new(true); - assert_eq!(a.fetch_and(false, SeqCst), true); - assert_eq!(a.load(SeqCst), false); -} - -#[test] -fn bool_nand() { - let a = AtomicBool::new(false); - assert_eq!(a.fetch_nand(false, SeqCst), false); - assert_eq!(a.load(SeqCst), true); - assert_eq!(a.fetch_nand(false, SeqCst), true); - assert_eq!(a.load(SeqCst), true); - assert_eq!(a.fetch_nand(true, SeqCst), true); - assert_eq!(a.load(SeqCst), false); - assert_eq!(a.fetch_nand(true, SeqCst), false); - assert_eq!(a.load(SeqCst), true); -} - -#[test] -fn uint_and() { - let x = AtomicUsize::new(0xf731); - assert_eq!(x.fetch_and(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0xf731 & 0x137f); -} - -#[test] -fn uint_nand() { - let x = AtomicUsize::new(0xf731); - assert_eq!(x.fetch_nand(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), !(0xf731 & 0x137f)); -} - -#[test] -fn uint_or() { - let x = AtomicUsize::new(0xf731); - assert_eq!(x.fetch_or(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0xf731 | 0x137f); -} - -#[test] -fn uint_xor() { - let x = AtomicUsize::new(0xf731); - assert_eq!(x.fetch_xor(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f); -} - -#[test] -#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins -fn uint_min() { - let x = AtomicUsize::new(0xf731); - assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0x137f); - assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f); - assert_eq!(x.load(SeqCst), 0x137f); -} - -#[test] -#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins -fn uint_max() { - let x = AtomicUsize::new(0x137f); - assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); - assert_eq!(x.load(SeqCst), 0xf731); - assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0xf731); -} - -#[test] -fn int_and() { - let x = AtomicIsize::new(0xf731); - assert_eq!(x.fetch_and(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0xf731 & 0x137f); -} - -#[test] -fn int_nand() { - let x = AtomicIsize::new(0xf731); - assert_eq!(x.fetch_nand(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), !(0xf731 & 0x137f)); -} - -#[test] -fn int_or() { - let x = AtomicIsize::new(0xf731); - assert_eq!(x.fetch_or(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0xf731 | 0x137f); -} - -#[test] -fn int_xor() { - let x = AtomicIsize::new(0xf731); - assert_eq!(x.fetch_xor(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f); -} - -#[test] -#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins -fn int_min() { - let x = AtomicIsize::new(0xf731); - assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0x137f); - assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f); - assert_eq!(x.load(SeqCst), 0x137f); -} - -#[test] -#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins -fn int_max() { - let x = AtomicIsize::new(0x137f); - assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); - assert_eq!(x.load(SeqCst), 0xf731); - assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731); - assert_eq!(x.load(SeqCst), 0xf731); -} - -#[test] -#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins -fn ptr_add_null() { - let atom = AtomicPtr::::new(core::ptr::null_mut()); - assert_eq!(atom.fetch_ptr_add(1, SeqCst).addr(), 0); - assert_eq!(atom.load(SeqCst).addr(), 8); - - assert_eq!(atom.fetch_byte_add(1, SeqCst).addr(), 8); - assert_eq!(atom.load(SeqCst).addr(), 9); - - assert_eq!(atom.fetch_ptr_sub(1, SeqCst).addr(), 9); - assert_eq!(atom.load(SeqCst).addr(), 1); - - assert_eq!(atom.fetch_byte_sub(1, SeqCst).addr(), 1); - assert_eq!(atom.load(SeqCst).addr(), 0); -} - -#[test] -#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins -fn ptr_add_data() { - let num = 0i64; - let n = &num as *const i64 as *mut _; - let atom = AtomicPtr::::new(n); - assert_eq!(atom.fetch_ptr_add(1, SeqCst), n); - assert_eq!(atom.load(SeqCst), n.wrapping_add(1)); - - assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1)); - assert_eq!(atom.load(SeqCst), n); - let bytes_from_n = |b| n.wrapping_byte_add(b); - - assert_eq!(atom.fetch_byte_add(1, SeqCst), n); - assert_eq!(atom.load(SeqCst), bytes_from_n(1)); - - assert_eq!(atom.fetch_byte_add(5, SeqCst), bytes_from_n(1)); - assert_eq!(atom.load(SeqCst), bytes_from_n(6)); - - assert_eq!(atom.fetch_byte_sub(1, SeqCst), bytes_from_n(6)); - assert_eq!(atom.load(SeqCst), bytes_from_n(5)); - - assert_eq!(atom.fetch_byte_sub(5, SeqCst), bytes_from_n(5)); - assert_eq!(atom.load(SeqCst), n); -} - -#[test] -#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins -fn ptr_bitops() { - let atom = AtomicPtr::::new(core::ptr::null_mut()); - assert_eq!(atom.fetch_or(0b0111, SeqCst).addr(), 0); - assert_eq!(atom.load(SeqCst).addr(), 0b0111); - - assert_eq!(atom.fetch_and(0b1101, SeqCst).addr(), 0b0111); - assert_eq!(atom.load(SeqCst).addr(), 0b0101); - - assert_eq!(atom.fetch_xor(0b1111, SeqCst).addr(), 0b0101); - assert_eq!(atom.load(SeqCst).addr(), 0b1010); -} - -#[test] -#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins -fn ptr_bitops_tagging() { - #[repr(align(16))] - struct Tagme(#[allow(dead_code)] u128); - - let tagme = Tagme(1000); - let ptr = &tagme as *const Tagme as *mut Tagme; - let atom: AtomicPtr = AtomicPtr::new(ptr); - - const MASK_TAG: usize = 0b1111; - const MASK_PTR: usize = !MASK_TAG; - - assert_eq!(ptr.addr() & MASK_TAG, 0); - - assert_eq!(atom.fetch_or(0b0111, SeqCst), ptr); - assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b111)); - - assert_eq!(atom.fetch_and(MASK_PTR | 0b0010, SeqCst), ptr.map_addr(|a| a | 0b111)); - assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b0010)); - - assert_eq!(atom.fetch_xor(0b1011, SeqCst), ptr.map_addr(|a| a | 0b0010)); - assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b1001)); - - assert_eq!(atom.fetch_and(MASK_PTR, SeqCst), ptr.map_addr(|a| a | 0b1001)); - assert_eq!(atom.load(SeqCst), ptr); -} - -static S_FALSE: AtomicBool = AtomicBool::new(false); -static S_TRUE: AtomicBool = AtomicBool::new(true); -static S_INT: AtomicIsize = AtomicIsize::new(0); -static S_UINT: AtomicUsize = AtomicUsize::new(0); - -#[test] -fn static_init() { - // Note that we're not really testing the mutability here but it's important - // on Android at the moment (#49775) - assert!(!S_FALSE.swap(true, SeqCst)); - assert!(S_TRUE.swap(false, SeqCst)); - assert!(S_INT.fetch_add(1, SeqCst) == 0); - assert!(S_UINT.fetch_add(1, SeqCst) == 0); -} - -#[test] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#[allow(static_mut_refs)] -fn atomic_access_bool() { - static mut ATOMIC: AtomicBool = AtomicBool::new(false); - - unsafe { - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.store(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_or(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_and(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.fetch_nand(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_xor(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - } -} - -#[test] -fn atomic_alignment() { - use std::mem::{align_of, size_of}; - - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::>(), size_of::>()); - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "16")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "16")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "32")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "32")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "64")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "64")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "128")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "128")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::(), size_of::()); -} - -#[test] -fn atomic_compare_exchange() { - use Ordering::*; - - static ATOMIC: AtomicIsize = AtomicIsize::new(0); - - ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); - ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); -} - -/* FIXME(#110395) -#[test] -fn atomic_const_from() { - const _ATOMIC_U8: AtomicU8 = AtomicU8::from(1); - const _ATOMIC_BOOL: AtomicBool = AtomicBool::from(true); - const _ATOMIC_PTR: AtomicPtr = AtomicPtr::from(core::ptr::null_mut()); -} -*/ diff --git a/library/core/tests/bool.rs b/library/core/tests/bool.rs deleted file mode 100644 index 47f6459915b..00000000000 --- a/library/core/tests/bool.rs +++ /dev/null @@ -1,107 +0,0 @@ -use core::cmp::Ordering::{Equal, Greater, Less}; -use core::ops::{BitAnd, BitOr, BitXor}; - -#[test] -fn test_bool() { - assert_eq!(false.eq(&true), false); - assert_eq!(false == false, true); - assert_eq!(false != true, true); - assert_eq!(false.ne(&false), false); - - assert_eq!(false.bitand(false), false); - assert_eq!(true.bitand(false), false); - assert_eq!(false.bitand(true), false); - assert_eq!(true.bitand(true), true); - - assert_eq!(false & false, false); - assert_eq!(true & false, false); - assert_eq!(false & true, false); - assert_eq!(true & true, true); - - assert_eq!(false.bitor(false), false); - assert_eq!(true.bitor(false), true); - assert_eq!(false.bitor(true), true); - assert_eq!(true.bitor(true), true); - - assert_eq!(false | false, false); - assert_eq!(true | false, true); - assert_eq!(false | true, true); - assert_eq!(true | true, true); - - assert_eq!(false.bitxor(false), false); - assert_eq!(true.bitxor(false), true); - assert_eq!(false.bitxor(true), true); - assert_eq!(true.bitxor(true), false); - - assert_eq!(false ^ false, false); - assert_eq!(true ^ false, true); - assert_eq!(false ^ true, true); - assert_eq!(true ^ true, false); - - assert_eq!(!true, false); - assert_eq!(!false, true); - - let s = false.to_string(); - assert_eq!(s, "false"); - let s = true.to_string(); - assert_eq!(s, "true"); - - assert!(true > false); - assert!(!(false > true)); - - assert!(false < true); - assert!(!(true < false)); - - assert!(false <= false); - assert!(false >= false); - assert!(true <= true); - assert!(true >= true); - - assert!(false <= true); - assert!(!(false >= true)); - assert!(true >= false); - assert!(!(true <= false)); - - assert_eq!(true.cmp(&true), Equal); - assert_eq!(false.cmp(&false), Equal); - assert_eq!(true.cmp(&false), Greater); - assert_eq!(false.cmp(&true), Less); -} - -#[test] -pub fn test_bool_not() { - if !false { - assert!((true)); - } else { - assert!((false)); - } - if !true { - assert!((false)); - } else { - assert!((true)); - } -} - -#[test] -fn test_bool_to_option() { - assert_eq!(false.then_some(0), None); - assert_eq!(true.then_some(0), Some(0)); - assert_eq!(false.then(|| 0), None); - assert_eq!(true.then(|| 0), Some(0)); - - /* FIXME(#110395) - const fn zero() -> i32 { - 0 - } - - const A: Option = false.then_some(0); - const B: Option = true.then_some(0); - const C: Option = false.then(zero); - const D: Option = true.then(zero); - - assert_eq!(A, None); - assert_eq!(B, Some(0)); - assert_eq!(C, None); - assert_eq!(D, Some(0)); - */ -} diff --git a/library/core/tests/bstr.rs b/library/core/tests/bstr.rs deleted file mode 100644 index 5fecd0a4084..00000000000 --- a/library/core/tests/bstr.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![feature(bstr)] - -use core::ByteStr; - -#[test] -fn test_debug() { - assert_eq!( - r#""\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff""#, - format!("{:?}", ByteStr::new(b"\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff")), - ); -} - -#[test] -fn test_display() { - let b1 = ByteStr::new("abc"); - let b2 = ByteStr::new(b"\xf0\x28\x8c\xbc"); - - assert_eq!(&format!("{b1}"), "abc"); - assert_eq!(&format!("{b2}"), "�(��"); - - assert_eq!(&format!("{b1:<7}!"), "abc !"); - assert_eq!(&format!("{b1:>7}!"), " abc!"); - assert_eq!(&format!("{b1:^7}!"), " abc !"); - assert_eq!(&format!("{b1:^6}!"), " abc !"); - assert_eq!(&format!("{b1:-<7}!"), "abc----!"); - assert_eq!(&format!("{b1:->7}!"), "----abc!"); - assert_eq!(&format!("{b1:-^7}!"), "--abc--!"); - assert_eq!(&format!("{b1:-^6}!"), "-abc--!"); - - assert_eq!(&format!("{b2:<7}!"), "�(�� !"); - assert_eq!(&format!("{b2:>7}!"), " �(��!"); - assert_eq!(&format!("{b2:^7}!"), " �(�� !"); - assert_eq!(&format!("{b2:^6}!"), " �(�� !"); - assert_eq!(&format!("{b2:-<7}!"), "�(��---!"); - assert_eq!(&format!("{b2:->7}!"), "---�(��!"); - assert_eq!(&format!("{b2:-^7}!"), "-�(��--!"); - assert_eq!(&format!("{b2:-^6}!"), "-�(��-!"); - - assert_eq!(&format!("{b1:<2}!"), "abc!"); - assert_eq!(&format!("{b1:>2}!"), "abc!"); - assert_eq!(&format!("{b1:^2}!"), "abc!"); - assert_eq!(&format!("{b1:-<2}!"), "abc!"); - assert_eq!(&format!("{b1:->2}!"), "abc!"); - assert_eq!(&format!("{b1:-^2}!"), "abc!"); - - assert_eq!(&format!("{b2:<3}!"), "�(��!"); - assert_eq!(&format!("{b2:>3}!"), "�(��!"); - assert_eq!(&format!("{b2:^3}!"), "�(��!"); - assert_eq!(&format!("{b2:^2}!"), "�(��!"); - assert_eq!(&format!("{b2:-<3}!"), "�(��!"); - assert_eq!(&format!("{b2:->3}!"), "�(��!"); - assert_eq!(&format!("{b2:-^3}!"), "�(��!"); - assert_eq!(&format!("{b2:-^2}!"), "�(��!"); -} diff --git a/library/core/tests/cell.rs b/library/core/tests/cell.rs deleted file mode 100644 index d6a401c2b4d..00000000000 --- a/library/core/tests/cell.rs +++ /dev/null @@ -1,479 +0,0 @@ -use core::cell::*; - -#[test] -fn smoketest_unsafe_cell() { - let mut x = UnsafeCell::new(10); - let ref_mut = &mut x; - unsafe { - // The asserts are repeated in order to ensure that `get()` - // is non-mutating. - assert_eq!(*ref_mut.get(), 10); - assert_eq!(*ref_mut.get(), 10); - *ref_mut.get_mut() += 5; - assert_eq!(*ref_mut.get(), 15); - assert_eq!(*ref_mut.get(), 15); - assert_eq!(x.into_inner(), 15); - } -} - -#[test] -fn unsafe_cell_raw_get() { - let x = UnsafeCell::new(10); - let ptr = &x as *const UnsafeCell; - unsafe { - // The asserts are repeated in order to ensure that `raw_get()` - // is non-mutating. - assert_eq!(*UnsafeCell::raw_get(ptr), 10); - assert_eq!(*UnsafeCell::raw_get(ptr), 10); - *UnsafeCell::raw_get(ptr) += 5; - assert_eq!(*UnsafeCell::raw_get(ptr), 15); - assert_eq!(*UnsafeCell::raw_get(ptr), 15); - assert_eq!(x.into_inner(), 15); - } -} - -#[test] -fn smoketest_cell() { - let x = Cell::new(10); - assert_eq!(x, Cell::new(10)); - assert_eq!(x.get(), 10); - x.set(20); - assert_eq!(x, Cell::new(20)); - assert_eq!(x.get(), 20); - - let y = Cell::new((30, 40)); - assert_eq!(y, Cell::new((30, 40))); - assert_eq!(y.get(), (30, 40)); -} - -#[test] -fn cell_update() { - let x = Cell::new(10); - - assert_eq!(x.update(|x| x + 5), 15); - assert_eq!(x.get(), 15); - - assert_eq!(x.update(|x| x / 3), 5); - assert_eq!(x.get(), 5); -} - -#[test] -fn cell_has_sensible_show() { - let x = Cell::new("foo bar"); - assert!(format!("{x:?}").contains(x.get())); - - x.set("baz qux"); - assert!(format!("{x:?}").contains(x.get())); -} - -#[test] -fn ref_and_refmut_have_sensible_show() { - let refcell = RefCell::new("foo"); - - let refcell_refmut = refcell.borrow_mut(); - assert_eq!(format!("{refcell_refmut}"), "foo"); // Display - assert!(format!("{refcell_refmut:?}").contains("foo")); // Debug - drop(refcell_refmut); - - let refcell_ref = refcell.borrow(); - assert_eq!(format!("{refcell_ref}"), "foo"); // Display - assert!(format!("{refcell_ref:?}").contains("foo")); // Debug - drop(refcell_ref); -} - -#[test] -fn double_imm_borrow() { - let x = RefCell::new(0); - let _b1 = x.borrow(); - x.borrow(); -} - -#[test] -fn no_mut_then_imm_borrow() { - let x = RefCell::new(0); - let _b1 = x.borrow_mut(); - assert!(x.try_borrow().is_err()); -} - -#[test] -fn no_imm_then_borrow_mut() { - let x = RefCell::new(0); - let _b1 = x.borrow(); - assert!(x.try_borrow_mut().is_err()); -} - -#[test] -fn no_double_borrow_mut() { - let x = RefCell::new(0); - assert!(x.try_borrow().is_ok()); - let _b1 = x.borrow_mut(); - assert!(x.try_borrow().is_err()); -} - -#[test] -fn imm_release_borrow_mut() { - let x = RefCell::new(0); - { - let _b1 = x.borrow(); - } - x.borrow_mut(); -} - -#[test] -fn mut_release_borrow_mut() { - let x = RefCell::new(0); - { - let _b1 = x.borrow_mut(); - } - x.borrow(); -} - -#[test] -fn double_borrow_single_release_no_borrow_mut() { - let x = RefCell::new(0); - let _b1 = x.borrow(); - { - let _b2 = x.borrow(); - } - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_err()); -} - -#[test] -#[should_panic] -fn discard_doesnt_unborrow() { - let x = RefCell::new(0); - let _b = x.borrow(); - let _ = _b; - let _b = x.borrow_mut(); -} - -#[test] -fn ref_clone_updates_flag() { - let x = RefCell::new(0); - { - let b1 = x.borrow(); - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_err()); - { - let _b2 = Ref::clone(&b1); - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_err()); - } - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_err()); - } - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_ok()); -} - -#[test] -fn ref_map_does_not_update_flag() { - let x = RefCell::new(Some(5)); - { - let b1: Ref<'_, Option> = x.borrow(); - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_err()); - { - let b2: Ref<'_, u32> = Ref::map(b1, |o| o.as_ref().unwrap()); - assert_eq!(*b2, 5); - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_err()); - } - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_ok()); - } - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_ok()); -} - -#[test] -fn ref_map_split_updates_flag() { - let x = RefCell::new([1, 2]); - { - let b1 = x.borrow(); - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_err()); - { - let (_b2, _b3) = Ref::map_split(b1, |slc| slc.split_at(1)); - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_err()); - } - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_ok()); - } - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_ok()); - - { - let b1 = x.borrow_mut(); - assert!(x.try_borrow().is_err()); - assert!(x.try_borrow_mut().is_err()); - { - let (_b2, _b3) = RefMut::map_split(b1, |slc| slc.split_at_mut(1)); - assert!(x.try_borrow().is_err()); - assert!(x.try_borrow_mut().is_err()); - drop(_b2); - assert!(x.try_borrow().is_err()); - assert!(x.try_borrow_mut().is_err()); - } - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_ok()); - } - assert!(x.try_borrow().is_ok()); - assert!(x.try_borrow_mut().is_ok()); -} - -#[test] -fn ref_map_split() { - let x = RefCell::new([1, 2]); - let (b1, b2) = Ref::map_split(x.borrow(), |slc| slc.split_at(1)); - assert_eq!(*b1, [1]); - assert_eq!(*b2, [2]); -} - -#[test] -fn ref_mut_map_split() { - let x = RefCell::new([1, 2]); - { - let (mut b1, mut b2) = RefMut::map_split(x.borrow_mut(), |slc| slc.split_at_mut(1)); - assert_eq!(*b1, [1]); - assert_eq!(*b2, [2]); - b1[0] = 2; - b2[0] = 1; - } - assert_eq!(*x.borrow(), [2, 1]); -} - -#[test] -fn ref_map_accessor() { - struct X(RefCell<(u32, char)>); - impl X { - fn accessor(&self) -> Ref<'_, u32> { - Ref::map(self.0.borrow(), |tuple| &tuple.0) - } - } - let x = X(RefCell::new((7, 'z'))); - let d: Ref<'_, u32> = x.accessor(); - assert_eq!(*d, 7); -} - -#[test] -fn ref_mut_map_accessor() { - struct X(RefCell<(u32, char)>); - impl X { - fn accessor(&self) -> RefMut<'_, u32> { - RefMut::map(self.0.borrow_mut(), |tuple| &mut tuple.0) - } - } - let x = X(RefCell::new((7, 'z'))); - { - let mut d: RefMut<'_, u32> = x.accessor(); - assert_eq!(*d, 7); - *d += 1; - } - assert_eq!(*x.0.borrow(), (8, 'z')); -} - -#[test] -fn as_ptr() { - let c1: Cell = Cell::new(0); - c1.set(1); - assert_eq!(1, unsafe { *c1.as_ptr() }); - - let c2: Cell = Cell::new(0); - unsafe { - *c2.as_ptr() = 1; - } - assert_eq!(1, c2.get()); - - let r1: RefCell = RefCell::new(0); - *r1.borrow_mut() = 1; - assert_eq!(1, unsafe { *r1.as_ptr() }); - - let r2: RefCell = RefCell::new(0); - unsafe { - *r2.as_ptr() = 1; - } - assert_eq!(1, *r2.borrow()); -} - -#[test] -fn cell_default() { - let cell: Cell = Default::default(); - assert_eq!(0, cell.get()); -} - -#[test] -fn cell_set() { - let cell = Cell::new(10); - cell.set(20); - assert_eq!(20, cell.get()); - - let cell = Cell::new("Hello".to_owned()); - cell.set("World".to_owned()); - assert_eq!("World".to_owned(), cell.into_inner()); -} - -#[test] -fn cell_replace() { - let cell = Cell::new(10); - assert_eq!(10, cell.replace(20)); - assert_eq!(20, cell.get()); - - let cell = Cell::new("Hello".to_owned()); - assert_eq!("Hello".to_owned(), cell.replace("World".to_owned())); - assert_eq!("World".to_owned(), cell.into_inner()); -} - -#[test] -fn cell_into_inner() { - let cell = Cell::new(10); - assert_eq!(10, cell.into_inner()); - - let cell = Cell::new("Hello world".to_owned()); - assert_eq!("Hello world".to_owned(), cell.into_inner()); -} - -#[test] -fn cell_exterior() { - #[derive(Copy, Clone)] - #[allow(dead_code)] - struct Point { - x: isize, - y: isize, - z: isize, - } - - fn f(p: &Cell) { - assert_eq!(p.get().z, 12); - p.set(Point { x: 10, y: 11, z: 13 }); - assert_eq!(p.get().z, 13); - } - - let a = Point { x: 10, y: 11, z: 12 }; - let b = &Cell::new(a); - assert_eq!(b.get().z, 12); - f(b); - assert_eq!(a.z, 12); - assert_eq!(b.get().z, 13); -} - -#[test] -fn cell_does_not_clone() { - #[derive(Copy)] - #[allow(dead_code)] - struct Foo { - x: isize, - } - - impl Clone for Foo { - fn clone(&self) -> Foo { - // Using Cell in any way should never cause clone() to be - // invoked -- after all, that would permit evil user code to - // abuse `Cell` and trigger crashes. - - panic!(); - } - } - - let x = Cell::new(Foo { x: 22 }); - let _y = x.get(); - let _z = x.clone(); -} - -#[test] -fn refcell_default() { - let cell: RefCell = Default::default(); - assert_eq!(0, *cell.borrow()); -} - -#[test] -fn unsafe_cell_unsized() { - let cell: &UnsafeCell<[i32]> = &UnsafeCell::new([1, 2, 3]); - { - let val: &mut [i32] = unsafe { &mut *cell.get() }; - val[0] = 4; - val[2] = 5; - } - let comp: &mut [i32] = &mut [4, 2, 5]; - assert_eq!(unsafe { &mut *cell.get() }, comp); -} - -#[test] -fn refcell_unsized() { - let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); - { - let b = &mut *cell.borrow_mut(); - b[0] = 4; - b[2] = 5; - } - let comp: &mut [i32] = &mut [4, 2, 5]; - assert_eq!(&*cell.borrow(), comp); -} - -#[test] -fn refcell_ref_coercion() { - let cell: RefCell<[i32; 3]> = RefCell::new([1, 2, 3]); - { - let mut cellref: RefMut<'_, [i32; 3]> = cell.borrow_mut(); - cellref[0] = 4; - let mut coerced: RefMut<'_, [i32]> = cellref; - coerced[2] = 5; - } - { - let comp: &mut [i32] = &mut [4, 2, 5]; - let cellref: Ref<'_, [i32; 3]> = cell.borrow(); - assert_eq!(&*cellref, comp); - let coerced: Ref<'_, [i32]> = cellref; - assert_eq!(&*coerced, comp); - } -} - -#[test] -#[should_panic] -fn refcell_swap_borrows() { - let x = RefCell::new(0); - let _b = x.borrow(); - let y = RefCell::new(1); - x.swap(&y); -} - -#[test] -#[should_panic] -fn refcell_replace_borrows() { - let x = RefCell::new(0); - let _b = x.borrow(); - x.replace(1); -} - -#[test] -fn refcell_format() { - let name = RefCell::new("rust"); - let what = RefCell::new("rocks"); - let msg = format!("{name} {}", &*what.borrow(), name = &*name.borrow()); - assert_eq!(msg, "rust rocks".to_string()); -} - -#[allow(dead_code)] -fn const_cells() { - const UNSAFE_CELL: UnsafeCell = UnsafeCell::new(3); - const _: i32 = UNSAFE_CELL.into_inner(); - - const REF_CELL: RefCell = RefCell::new(3); - const _: i32 = REF_CELL.into_inner(); - - const CELL: Cell = Cell::new(3); - const _: i32 = CELL.into_inner(); - - /* FIXME(#110395) - const UNSAFE_CELL_FROM: UnsafeCell = UnsafeCell::from(3); - const _: i32 = UNSAFE_CELL.into_inner(); - - const REF_CELL_FROM: RefCell = RefCell::from(3); - const _: i32 = REF_CELL.into_inner(); - - const CELL_FROM: Cell = Cell::from(3); - const _: i32 = CELL.into_inner(); - */ -} diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs deleted file mode 100644 index 6422387e956..00000000000 --- a/library/core/tests/char.rs +++ /dev/null @@ -1,420 +0,0 @@ -use std::str::FromStr; -use std::{char, str}; - -#[test] -fn test_convert() { - assert_eq!(u32::from('a'), 0x61); - assert_eq!(u64::from('b'), 0x62); - assert_eq!(u128::from('c'), 0x63); - assert_eq!(char::from(b'\0'), '\0'); - assert_eq!(char::from(b'a'), 'a'); - assert_eq!(char::from(b'\xFF'), '\u{FF}'); - assert_eq!(char::try_from(0_u32), Ok('\0')); - assert_eq!(char::try_from(0x61_u32), Ok('a')); - assert_eq!(char::try_from(0xD7FF_u32), Ok('\u{D7FF}')); - assert!(char::try_from(0xD800_u32).is_err()); - assert!(char::try_from(0xDFFF_u32).is_err()); - assert_eq!(char::try_from(0xE000_u32), Ok('\u{E000}')); - assert_eq!(char::try_from(0x10FFFF_u32), Ok('\u{10FFFF}')); - assert!(char::try_from(0x110000_u32).is_err()); - assert!(char::try_from(0xFFFF_FFFF_u32).is_err()); -} - -/* FIXME(#110395) -#[test] -const fn test_convert_const() { - assert!(u32::from('a') == 0x61); - assert!(u64::from('b') == 0x62); - assert!(u128::from('c') == 0x63); - assert!(char::from(b'\0') == '\0'); - assert!(char::from(b'a') == 'a'); - assert!(char::from(b'\xFF') == '\u{FF}'); -} -*/ - -#[test] -fn test_from_str() { - assert_eq!(char::from_str("a").unwrap(), 'a'); - assert_eq!(char::from_str("\0").unwrap(), '\0'); - assert_eq!(char::from_str("\u{D7FF}").unwrap(), '\u{d7FF}'); - assert!(char::from_str("").is_err()); - assert!(char::from_str("abc").is_err()); -} - -#[test] -fn test_is_lowercase() { - assert!('a'.is_lowercase()); - assert!('ö'.is_lowercase()); - assert!('ß'.is_lowercase()); - assert!(!'Ü'.is_lowercase()); - assert!(!'P'.is_lowercase()); -} - -#[test] -fn test_is_uppercase() { - assert!(!'h'.is_uppercase()); - assert!(!'ä'.is_uppercase()); - assert!(!'ß'.is_uppercase()); - assert!('Ö'.is_uppercase()); - assert!('T'.is_uppercase()); -} - -#[test] -fn test_is_whitespace() { - assert!(' '.is_whitespace()); - assert!('\u{2007}'.is_whitespace()); - assert!('\t'.is_whitespace()); - assert!('\n'.is_whitespace()); - assert!(!'a'.is_whitespace()); - assert!(!'_'.is_whitespace()); - assert!(!'\u{0}'.is_whitespace()); -} - -#[test] -fn test_to_digit() { - assert_eq!('0'.to_digit(10), Some(0)); - assert_eq!('1'.to_digit(2), Some(1)); - assert_eq!('2'.to_digit(3), Some(2)); - assert_eq!('9'.to_digit(10), Some(9)); - assert_eq!('a'.to_digit(16), Some(10)); - assert_eq!('A'.to_digit(16), Some(10)); - assert_eq!('b'.to_digit(16), Some(11)); - assert_eq!('B'.to_digit(16), Some(11)); - assert_eq!('A'.to_digit(36), Some(10)); - assert_eq!('z'.to_digit(36), Some(35)); - assert_eq!('Z'.to_digit(36), Some(35)); - assert_eq!('['.to_digit(36), None); - assert_eq!('`'.to_digit(36), None); - assert_eq!('{'.to_digit(36), None); - assert_eq!('$'.to_digit(36), None); - assert_eq!('@'.to_digit(16), None); - assert_eq!('G'.to_digit(16), None); - assert_eq!('g'.to_digit(16), None); - assert_eq!(' '.to_digit(10), None); - assert_eq!('/'.to_digit(10), None); - assert_eq!(':'.to_digit(10), None); - assert_eq!(':'.to_digit(11), None); -} - -#[test] -fn test_to_lowercase() { - fn lower(c: char) -> String { - let to_lowercase = c.to_lowercase(); - assert_eq!(to_lowercase.len(), to_lowercase.count()); - let iter: String = c.to_lowercase().collect(); - let disp: String = c.to_lowercase().to_string(); - assert_eq!(iter, disp); - let iter_rev: String = c.to_lowercase().rev().collect(); - let disp_rev: String = disp.chars().rev().collect(); - assert_eq!(iter_rev, disp_rev); - iter - } - assert_eq!(lower('A'), "a"); - assert_eq!(lower('Ö'), "ö"); - assert_eq!(lower('ß'), "ß"); - assert_eq!(lower('Ü'), "ü"); - assert_eq!(lower('💩'), "💩"); - assert_eq!(lower('Σ'), "σ"); - assert_eq!(lower('Τ'), "τ"); - assert_eq!(lower('Ι'), "ι"); - assert_eq!(lower('Γ'), "γ"); - assert_eq!(lower('Μ'), "μ"); - assert_eq!(lower('Α'), "α"); - assert_eq!(lower('Σ'), "σ"); - assert_eq!(lower('Dž'), "dž"); - assert_eq!(lower('fi'), "fi"); - assert_eq!(lower('İ'), "i\u{307}"); -} - -#[test] -fn test_to_uppercase() { - fn upper(c: char) -> String { - let to_uppercase = c.to_uppercase(); - assert_eq!(to_uppercase.len(), to_uppercase.count()); - let iter: String = c.to_uppercase().collect(); - let disp: String = c.to_uppercase().to_string(); - assert_eq!(iter, disp); - let iter_rev: String = c.to_uppercase().rev().collect(); - let disp_rev: String = disp.chars().rev().collect(); - assert_eq!(iter_rev, disp_rev); - iter - } - assert_eq!(upper('a'), "A"); - assert_eq!(upper('ö'), "Ö"); - assert_eq!(upper('ß'), "SS"); // not ẞ: Latin capital letter sharp s - assert_eq!(upper('ü'), "Ü"); - assert_eq!(upper('💩'), "💩"); - - assert_eq!(upper('σ'), "Σ"); - assert_eq!(upper('τ'), "Τ"); - assert_eq!(upper('ι'), "Ι"); - assert_eq!(upper('γ'), "Γ"); - assert_eq!(upper('μ'), "Μ"); - assert_eq!(upper('α'), "Α"); - assert_eq!(upper('ς'), "Σ"); - assert_eq!(upper('Dž'), "DŽ"); - assert_eq!(upper('fi'), "FI"); - assert_eq!(upper('ᾀ'), "ἈΙ"); -} - -#[test] -fn test_is_control() { - assert!('\u{0}'.is_control()); - assert!('\u{3}'.is_control()); - assert!('\u{6}'.is_control()); - assert!('\u{9}'.is_control()); - assert!('\u{7f}'.is_control()); - assert!('\u{92}'.is_control()); - assert!(!'\u{20}'.is_control()); - assert!(!'\u{55}'.is_control()); - assert!(!'\u{68}'.is_control()); -} - -#[test] -fn test_is_numeric() { - assert!('2'.is_numeric()); - assert!('7'.is_numeric()); - assert!('¾'.is_numeric()); - assert!(!'c'.is_numeric()); - assert!(!'i'.is_numeric()); - assert!(!'z'.is_numeric()); - assert!(!'Q'.is_numeric()); -} - -#[test] -fn test_escape_debug() { - fn string(c: char) -> String { - let iter: String = c.escape_debug().collect(); - let disp: String = c.escape_debug().to_string(); - assert_eq!(iter, disp); - iter - } - assert_eq!(string('\n'), "\\n"); - assert_eq!(string('\r'), "\\r"); - assert_eq!(string('\''), "\\'"); - assert_eq!(string('"'), "\\\""); - assert_eq!(string(' '), " "); - assert_eq!(string('a'), "a"); - assert_eq!(string('~'), "~"); - assert_eq!(string('é'), "é"); - assert_eq!(string('文'), "文"); - assert_eq!(string('\x00'), "\\0"); - assert_eq!(string('\x1f'), "\\u{1f}"); - assert_eq!(string('\x7f'), "\\u{7f}"); - assert_eq!(string('\u{80}'), "\\u{80}"); - assert_eq!(string('\u{ff}'), "\u{ff}"); - assert_eq!(string('\u{11b}'), "\u{11b}"); - assert_eq!(string('\u{1d4b6}'), "\u{1d4b6}"); - assert_eq!(string('\u{301}'), "\\u{301}"); // combining character - assert_eq!(string('\u{200b}'), "\\u{200b}"); // zero width space - assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1 - assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 -} - -#[test] -fn test_escape_default() { - fn string(c: char) -> String { - let iter: String = c.escape_default().collect(); - let disp: String = c.escape_default().to_string(); - assert_eq!(iter, disp); - iter - } - assert_eq!(string('\n'), "\\n"); - assert_eq!(string('\r'), "\\r"); - assert_eq!(string('\''), "\\'"); - assert_eq!(string('"'), "\\\""); - assert_eq!(string(' '), " "); - assert_eq!(string('a'), "a"); - assert_eq!(string('~'), "~"); - assert_eq!(string('é'), "\\u{e9}"); - assert_eq!(string('\x00'), "\\u{0}"); - assert_eq!(string('\x1f'), "\\u{1f}"); - assert_eq!(string('\x7f'), "\\u{7f}"); - assert_eq!(string('\u{80}'), "\\u{80}"); - assert_eq!(string('\u{ff}'), "\\u{ff}"); - assert_eq!(string('\u{11b}'), "\\u{11b}"); - assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}"); - assert_eq!(string('\u{200b}'), "\\u{200b}"); // zero width space - assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1 - assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 -} - -#[test] -fn test_escape_unicode() { - fn string(c: char) -> String { - let iter: String = c.escape_unicode().collect(); - let disp: String = c.escape_unicode().to_string(); - assert_eq!(iter, disp); - iter - } - - assert_eq!(string('\x00'), "\\u{0}"); - assert_eq!(string('\n'), "\\u{a}"); - assert_eq!(string(' '), "\\u{20}"); - assert_eq!(string('a'), "\\u{61}"); - assert_eq!(string('\u{11b}'), "\\u{11b}"); - assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}"); -} - -#[test] -fn test_encode_utf8() { - fn check(input: char, expect: &[u8]) { - let mut buf = [0; 4]; - let ptr = buf.as_ptr(); - let s = input.encode_utf8(&mut buf); - assert_eq!(s.as_ptr() as usize, ptr as usize); - assert!(str::from_utf8(s.as_bytes()).is_ok()); - assert_eq!(s.as_bytes(), expect); - } - - check('x', &[0x78]); - check('\u{e9}', &[0xc3, 0xa9]); - check('\u{a66e}', &[0xea, 0x99, 0xae]); - check('\u{1f4a9}', &[0xf0, 0x9f, 0x92, 0xa9]); -} - -#[test] -fn test_encode_utf16() { - fn check(input: char, expect: &[u16]) { - let mut buf = [0; 2]; - let ptr = buf.as_mut_ptr(); - let b = input.encode_utf16(&mut buf); - assert_eq!(b.as_mut_ptr() as usize, ptr as usize); - assert_eq!(b, expect); - } - - check('x', &[0x0078]); - check('\u{e9}', &[0x00e9]); - check('\u{a66e}', &[0xa66e]); - check('\u{1f4a9}', &[0xd83d, 0xdca9]); -} - -#[test] -fn test_len_utf16() { - assert!('x'.len_utf16() == 1); - assert!('\u{e9}'.len_utf16() == 1); - assert!('\u{a66e}'.len_utf16() == 1); - assert!('\u{1f4a9}'.len_utf16() == 2); -} - -#[test] -fn test_decode_utf16() { - fn check(s: &[u16], expected: &[Result]) { - let v = char::decode_utf16(s.iter().cloned()) - .map(|r| r.map_err(|e| e.unpaired_surrogate())) - .collect::>(); - assert_eq!(v, expected); - } - check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]); - check(&[0xD800, 0], &[Err(0xD800), Ok('\0')]); - check(&[0xD800], &[Err(0xD800)]); - check(&[0xD840, 0xDC00], &[Ok('\u{20000}')]); - check(&[0xD840, 0xD840, 0xDC00], &[Err(0xD840), Ok('\u{20000}')]); - check(&[0xDC00, 0xD840], &[Err(0xDC00), Err(0xD840)]); -} - -#[test] -fn test_decode_utf16_size_hint() { - fn check(s: &[u16]) { - let mut iter = char::decode_utf16(s.iter().cloned()); - - loop { - let count = iter.clone().count(); - let (lower, upper) = iter.size_hint(); - - assert!( - lower <= count && count <= upper.unwrap(), - "lower = {lower}, count = {count}, upper = {upper:?}" - ); - - if let None = iter.next() { - break; - } - } - } - - check(&[0xD800, 0xD800, 0xDC00]); - check(&[0xD800, 0xD800, 0x0]); - check(&[0xD800, 0x41, 0x42]); - check(&[0xD800, 0]); - check(&[0xD834, 0x006d]); -} - -#[test] -fn ed_iterator_specializations() { - // Check counting - assert_eq!('\n'.escape_default().count(), 2); - assert_eq!('c'.escape_default().count(), 1); - assert_eq!(' '.escape_default().count(), 1); - assert_eq!('\\'.escape_default().count(), 2); - assert_eq!('\''.escape_default().count(), 2); - - // Check nth - - // Check that OoB is handled correctly - assert_eq!('\n'.escape_default().nth(2), None); - assert_eq!('c'.escape_default().nth(1), None); - assert_eq!(' '.escape_default().nth(1), None); - assert_eq!('\\'.escape_default().nth(2), None); - assert_eq!('\''.escape_default().nth(2), None); - - // Check the first char - assert_eq!('\n'.escape_default().nth(0), Some('\\')); - assert_eq!('c'.escape_default().nth(0), Some('c')); - assert_eq!(' '.escape_default().nth(0), Some(' ')); - assert_eq!('\\'.escape_default().nth(0), Some('\\')); - assert_eq!('\''.escape_default().nth(0), Some('\\')); - - // Check the second char - assert_eq!('\n'.escape_default().nth(1), Some('n')); - assert_eq!('\\'.escape_default().nth(1), Some('\\')); - assert_eq!('\''.escape_default().nth(1), Some('\'')); - - // Check the last char - assert_eq!('\n'.escape_default().last(), Some('n')); - assert_eq!('c'.escape_default().last(), Some('c')); - assert_eq!(' '.escape_default().last(), Some(' ')); - assert_eq!('\\'.escape_default().last(), Some('\\')); - assert_eq!('\''.escape_default().last(), Some('\'')); -} - -#[test] -fn eu_iterator_specializations() { - fn check(c: char) { - let len = c.escape_unicode().count(); - - // Check OoB - assert_eq!(c.escape_unicode().nth(len), None); - - // For all possible in-bound offsets - let mut iter = c.escape_unicode(); - for offset in 0..len { - // Check last - assert_eq!(iter.clone().last(), Some('}')); - - // Check len - assert_eq!(iter.len(), len - offset); - - // Check size_hint (= len in ExactSizeIterator) - assert_eq!(iter.size_hint(), (iter.len(), Some(iter.len()))); - - // Check counting - assert_eq!(iter.clone().count(), len - offset); - - // Check nth - assert_eq!(c.escape_unicode().nth(offset), iter.next()); - } - - // Check post-last - assert_eq!(iter.clone().last(), None); - assert_eq!(iter.clone().count(), 0); - } - - check('\u{0}'); - check('\u{1}'); - check('\u{12}'); - check('\u{123}'); - check('\u{1234}'); - check('\u{12340}'); - check('\u{10FFFF}'); -} diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs deleted file mode 100644 index 054b1d3d498..00000000000 --- a/library/core/tests/clone.rs +++ /dev/null @@ -1,123 +0,0 @@ -use core::clone::CloneToUninit; -use core::ffi::CStr; -use core::mem::MaybeUninit; -use core::ptr; - -#[test] -#[allow(suspicious_double_ref_op)] -fn test_borrowed_clone() { - let x = 5; - let y: &i32 = &x; - let z: &i32 = (&y).clone(); - assert_eq!(*z, 5); -} - -#[test] -fn test_clone_from() { - let a = Box::new(5); - let mut b = Box::new(10); - b.clone_from(&a); - assert_eq!(*b, 5); -} - -#[test] -fn test_clone_to_uninit_slice_success() { - // Using `String`s to exercise allocation and Drop of the individual elements; - // if something is aliased or double-freed, at least Miri will catch that. - let a: [String; 3] = ["a", "b", "c"].map(String::from); - - let mut storage: MaybeUninit<[String; 3]> = MaybeUninit::uninit(); - let b: [String; 3] = unsafe { - a[..].clone_to_uninit(storage.as_mut_ptr().cast()); - storage.assume_init() - }; - - assert_eq!(a, b); -} - -#[test] -#[cfg(panic = "unwind")] -fn test_clone_to_uninit_slice_drops_on_panic() { - use core::sync::atomic::AtomicUsize; - use core::sync::atomic::Ordering::Relaxed; - - /// A static counter is OK to use as long as _this one test_ isn't run several times in - /// multiple threads. - static COUNTER: AtomicUsize = AtomicUsize::new(0); - /// Counts how many instances are live, and panics if a fifth one is created - struct CountsDropsAndPanics {} - impl CountsDropsAndPanics { - fn new() -> Self { - COUNTER.fetch_add(1, Relaxed); - Self {} - } - } - impl Clone for CountsDropsAndPanics { - fn clone(&self) -> Self { - if COUNTER.load(Relaxed) == 4 { panic!("intentional panic") } else { Self::new() } - } - } - impl Drop for CountsDropsAndPanics { - fn drop(&mut self) { - COUNTER.fetch_sub(1, Relaxed); - } - } - - let a: [CountsDropsAndPanics; 3] = core::array::from_fn(|_| CountsDropsAndPanics::new()); - assert_eq!(COUNTER.load(Relaxed), 3); - - let panic_payload = std::panic::catch_unwind(|| { - let mut storage: MaybeUninit<[CountsDropsAndPanics; 3]> = MaybeUninit::uninit(); - // This should panic halfway through - unsafe { - a[..].clone_to_uninit(storage.as_mut_ptr().cast()); - } - }) - .unwrap_err(); - assert_eq!(panic_payload.downcast().unwrap(), Box::new("intentional panic")); - - // Check for lack of leak, which is what this test is looking for - assert_eq!(COUNTER.load(Relaxed), 3, "leaked during clone!"); - - // Might as well exercise the rest of the drops - drop(a); - assert_eq!(COUNTER.load(Relaxed), 0); -} - -#[test] -fn test_clone_to_uninit_str() { - let a = "hello"; - - let mut storage: MaybeUninit<[u8; 5]> = MaybeUninit::uninit(); - unsafe { a.clone_to_uninit(storage.as_mut_ptr().cast()) }; - assert_eq!(a.as_bytes(), unsafe { storage.assume_init() }.as_slice()); - - let mut b: Box = "world".into(); - assert_eq!(a.len(), b.len()); - assert_ne!(a, &*b); - unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; - assert_eq!(a, &*b); -} - -#[test] -fn test_clone_to_uninit_cstr() { - let a = c"hello"; - - let mut storage: MaybeUninit<[u8; 6]> = MaybeUninit::uninit(); - unsafe { a.clone_to_uninit(storage.as_mut_ptr().cast()) }; - assert_eq!(a.to_bytes_with_nul(), unsafe { storage.assume_init() }.as_slice()); - - let mut b: Box = c"world".into(); - assert_eq!(a.count_bytes(), b.count_bytes()); - assert_ne!(a, &*b); - unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; - assert_eq!(a, &*b); -} - -#[test] -fn cstr_metadata_is_length_with_nul() { - let s: &CStr = c"abcdef"; - let p: *const CStr = ptr::from_ref(s); - let bytes: *const [u8] = p as *const [u8]; - assert_eq!(s.to_bytes_with_nul().len(), bytes.len()); -} diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs deleted file mode 100644 index 6c4e2146f91..00000000000 --- a/library/core/tests/cmp.rs +++ /dev/null @@ -1,250 +0,0 @@ -use core::cmp::Ordering::{self, *}; -use core::cmp::{self}; - -#[test] -fn test_int_totalord() { - assert_eq!(5.cmp(&10), Less); - assert_eq!(10.cmp(&5), Greater); - assert_eq!(5.cmp(&5), Equal); - assert_eq!((-5).cmp(&12), Less); - assert_eq!(12.cmp(&-5), Greater); -} - -#[test] -fn test_bool_totalord() { - assert_eq!(true.cmp(&false), Greater); - assert_eq!(false.cmp(&true), Less); - assert_eq!(true.cmp(&true), Equal); - assert_eq!(false.cmp(&false), Equal); -} - -#[test] -fn test_mut_int_totalord() { - assert_eq!((&mut 5).cmp(&&mut 10), Less); - assert_eq!((&mut 10).cmp(&&mut 5), Greater); - assert_eq!((&mut 5).cmp(&&mut 5), Equal); - assert_eq!((&mut -5).cmp(&&mut 12), Less); - assert_eq!((&mut 12).cmp(&&mut -5), Greater); -} - -#[test] -fn test_ord_max_min() { - assert_eq!(1.max(2), 2); - assert_eq!(2.max(1), 2); - assert_eq!(1.min(2), 1); - assert_eq!(2.min(1), 1); - assert_eq!(1.max(1), 1); - assert_eq!(1.min(1), 1); -} - -#[test] -fn test_ord_min_max_by() { - let f = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); - assert_eq!(cmp::min_by(1, -1, f), 1); - assert_eq!(cmp::min_by(1, -2, f), 1); - assert_eq!(cmp::min_by(2, -1, f), -1); - assert_eq!(cmp::max_by(1, -1, f), -1); - assert_eq!(cmp::max_by(1, -2, f), -2); - assert_eq!(cmp::max_by(2, -1, f), 2); -} - -#[test] -fn test_ord_min_max_by_key() { - let f = |x: &i32| x.abs(); - assert_eq!(cmp::min_by_key(1, -1, f), 1); - assert_eq!(cmp::min_by_key(1, -2, f), 1); - assert_eq!(cmp::min_by_key(2, -1, f), -1); - assert_eq!(cmp::max_by_key(1, -1, f), -1); - assert_eq!(cmp::max_by_key(1, -2, f), -2); - assert_eq!(cmp::max_by_key(2, -1, f), 2); -} - -#[test] -fn test_ordering_reverse() { - assert_eq!(Less.reverse(), Greater); - assert_eq!(Equal.reverse(), Equal); - assert_eq!(Greater.reverse(), Less); -} - -#[test] -fn test_ordering_order() { - assert!(Less < Equal); - assert_eq!(Greater.cmp(&Less), Greater); -} - -#[test] -fn test_ordering_then() { - assert_eq!(Equal.then(Less), Less); - assert_eq!(Equal.then(Equal), Equal); - assert_eq!(Equal.then(Greater), Greater); - assert_eq!(Less.then(Less), Less); - assert_eq!(Less.then(Equal), Less); - assert_eq!(Less.then(Greater), Less); - assert_eq!(Greater.then(Less), Greater); - assert_eq!(Greater.then(Equal), Greater); - assert_eq!(Greater.then(Greater), Greater); -} - -#[test] -fn test_ordering_then_with() { - assert_eq!(Equal.then_with(|| Less), Less); - assert_eq!(Equal.then_with(|| Equal), Equal); - assert_eq!(Equal.then_with(|| Greater), Greater); - assert_eq!(Less.then_with(|| Less), Less); - assert_eq!(Less.then_with(|| Equal), Less); - assert_eq!(Less.then_with(|| Greater), Less); - assert_eq!(Greater.then_with(|| Less), Greater); - assert_eq!(Greater.then_with(|| Equal), Greater); - assert_eq!(Greater.then_with(|| Greater), Greater); -} - -#[test] -fn test_user_defined_eq() { - // Our type. - struct SketchyNum { - num: isize, - } - - // Our implementation of `PartialEq` to support `==` and `!=`. - impl PartialEq for SketchyNum { - // Our custom eq allows numbers which are near each other to be equal! :D - fn eq(&self, other: &SketchyNum) -> bool { - (self.num - other.num).abs() < 5 - } - } - - // Now these binary operators will work when applied! - assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 }); - assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 }); -} - -#[test] -fn ordering_const() { - // test that the methods of `Ordering` are usable in a const context - - const ORDERING: Ordering = Greater; - - const REVERSE: Ordering = ORDERING.reverse(); - assert_eq!(REVERSE, Less); - - const THEN: Ordering = Equal.then(ORDERING); - assert_eq!(THEN, Greater); -} - -#[test] -fn ordering_structural_eq() { - // test that consts of type `Ordering` are usable in patterns - - const ORDERING: Ordering = Greater; - - const REVERSE: Ordering = ORDERING.reverse(); - match Ordering::Less { - REVERSE => {} - _ => unreachable!(), - }; -} - -#[test] -fn cmp_default() { - // Test default methods in PartialOrd and PartialEq - - #[derive(Debug)] - struct Fool(bool); - - impl PartialEq for Fool { - fn eq(&self, other: &Fool) -> bool { - let Fool(this) = *self; - let Fool(other) = *other; - this != other - } - } - - struct Int(isize); - - impl PartialEq for Int { - fn eq(&self, other: &Int) -> bool { - let Int(this) = *self; - let Int(other) = *other; - this == other - } - } - - impl PartialOrd for Int { - fn partial_cmp(&self, other: &Int) -> Option { - let Int(this) = *self; - let Int(other) = *other; - this.partial_cmp(&other) - } - } - - struct RevInt(isize); - - impl PartialEq for RevInt { - fn eq(&self, other: &RevInt) -> bool { - let RevInt(this) = *self; - let RevInt(other) = *other; - this == other - } - } - - impl PartialOrd for RevInt { - fn partial_cmp(&self, other: &RevInt) -> Option { - let RevInt(this) = *self; - let RevInt(other) = *other; - other.partial_cmp(&this) - } - } - - assert!(Int(2) > Int(1)); - assert!(Int(2) >= Int(1)); - assert!(Int(1) >= Int(1)); - assert!(Int(1) < Int(2)); - assert!(Int(1) <= Int(2)); - assert!(Int(1) <= Int(1)); - - assert!(RevInt(2) < RevInt(1)); - assert!(RevInt(2) <= RevInt(1)); - assert!(RevInt(1) <= RevInt(1)); - assert!(RevInt(1) > RevInt(2)); - assert!(RevInt(1) >= RevInt(2)); - assert!(RevInt(1) >= RevInt(1)); - - assert_eq!(Fool(true), Fool(false)); - assert!(Fool(true) != Fool(true)); - assert!(Fool(false) != Fool(false)); - assert_eq!(Fool(false), Fool(true)); -} - -/* FIXME(#110395) -mod const_cmp { - use super::*; - - struct S(i32); - - impl PartialEq for S { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl PartialOrd for S { - fn partial_cmp(&self, other: &Self) -> Option { - let ret = match (self.0, other.0) { - (a, b) if a > b => Ordering::Greater, - (a, b) if a < b => Ordering::Less, - _ => Ordering::Equal, - }; - - Some(ret) - } - } - - const _: () = assert!(S(1) == S(1)); - const _: () = assert!(S(0) != S(1)); - - const _: () = assert!(S(1) <= S(1)); - const _: () = assert!(S(1) >= S(1)); - const _: () = assert!(S(0) < S(1)); - const _: () = assert!(S(1) > S(0)); -} -*/ diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs deleted file mode 100644 index d874f08317f..00000000000 --- a/library/core/tests/const_ptr.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Aligned to two bytes -const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x45, 0x67])]; - -const fn unaligned_ptr() -> *const u16 { - // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16 - unsafe { DATA.as_ptr().byte_add(1) } -} - -#[test] -fn read() { - use core::ptr; - - const FOO: i32 = unsafe { ptr::read(&42 as *const i32) }; - assert_eq!(FOO, 42); - - const ALIGNED: i32 = unsafe { ptr::read_unaligned(&42 as *const i32) }; - assert_eq!(ALIGNED, 42); - - const UNALIGNED_PTR: *const u16 = unaligned_ptr(); - - const UNALIGNED: u16 = unsafe { ptr::read_unaligned(UNALIGNED_PTR) }; - assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); -} - -#[test] -fn const_ptr_read() { - const FOO: i32 = unsafe { (&42 as *const i32).read() }; - assert_eq!(FOO, 42); - - const ALIGNED: i32 = unsafe { (&42 as *const i32).read_unaligned() }; - assert_eq!(ALIGNED, 42); - - const UNALIGNED_PTR: *const u16 = unaligned_ptr(); - - const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; - assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); -} - -#[test] -fn mut_ptr_read() { - const FOO: i32 = unsafe { (&42 as *const i32 as *mut i32).read() }; - assert_eq!(FOO, 42); - - const ALIGNED: i32 = unsafe { (&42 as *const i32 as *mut i32).read_unaligned() }; - assert_eq!(ALIGNED, 42); - - const UNALIGNED_PTR: *mut u16 = unaligned_ptr() as *mut u16; - - const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; - assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); -} - -#[test] -fn write() { - use core::ptr; - - const fn write_aligned() -> i32 { - let mut res = 0; - unsafe { - ptr::write(&mut res as *mut _, 42); - } - res - } - const ALIGNED: i32 = write_aligned(); - assert_eq!(ALIGNED, 42); - - const fn write_unaligned() -> [u16; 2] { - let mut two_aligned = [0u16; 2]; - unsafe { - let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); - ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); - } - two_aligned - } - const UNALIGNED: [u16; 2] = write_unaligned(); - assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); -} - -#[test] -fn mut_ptr_write() { - const fn aligned() -> i32 { - let mut res = 0; - unsafe { - (&mut res as *mut i32).write(42); - } - res - } - const ALIGNED: i32 = aligned(); - assert_eq!(ALIGNED, 42); - - const fn write_unaligned() -> [u16; 2] { - let mut two_aligned = [0u16; 2]; - unsafe { - let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); - unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); - } - two_aligned - } - const UNALIGNED: [u16; 2] = write_unaligned(); - assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); -} diff --git a/library/core/tests/convert.rs b/library/core/tests/convert.rs deleted file mode 100644 index f76dd277884..00000000000 --- a/library/core/tests/convert.rs +++ /dev/null @@ -1,18 +0,0 @@ -/* FIXME(#110395) -#[test] -fn convert() { - const fn from(x: i32) -> i32 { - i32::from(x) - } - - const FOO: i32 = from(42); - assert_eq!(FOO, 42); - - const fn into(x: Vec) -> Vec { - x.into() - } - - const BAR: Vec = into(Vec::new()); - assert_eq!(BAR, Vec::::new()); -} -*/ diff --git a/library/core/tests/error.rs b/library/core/tests/error.rs deleted file mode 100644 index 996566d3848..00000000000 --- a/library/core/tests/error.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::error::{Request, request_ref, request_value}; - -// Test the `Request` API. -#[derive(Debug)] -struct SomeConcreteType { - some_string: String, -} - -impl std::fmt::Display for SomeConcreteType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "A") - } -} - -impl std::error::Error for SomeConcreteType { - fn provide<'a>(&'a self, request: &mut Request<'a>) { - request - .provide_ref::(&self.some_string) - .provide_ref::(&self.some_string) - .provide_value_with::(|| "bye".to_owned()); - } -} - -// Test the Error.provide and request mechanisms with a by-reference trait object. -#[test] -fn test_error_generic_member_access() { - let obj = &SomeConcreteType { some_string: "hello".to_owned() }; - - assert_eq!(request_ref::(&*obj).unwrap(), "hello"); - assert_eq!(request_value::(&*obj).unwrap(), "bye"); - assert_eq!(request_value::(&obj), None); -} - -// Test the Error.provide and request mechanisms with a by-reference trait object. -#[test] -fn test_request_constructor() { - let obj: &dyn std::error::Error = &SomeConcreteType { some_string: "hello".to_owned() }; - - assert_eq!(request_ref::(&*obj).unwrap(), "hello"); - assert_eq!(request_value::(&*obj).unwrap(), "bye"); - assert_eq!(request_value::(&obj), None); -} - -// Test the Error.provide and request mechanisms with a boxed trait object. -#[test] -fn test_error_generic_member_access_boxed() { - let obj: Box = - Box::new(SomeConcreteType { some_string: "hello".to_owned() }); - - assert_eq!(request_ref::(&*obj).unwrap(), "hello"); - assert_eq!(request_value::(&*obj).unwrap(), "bye"); - - // NOTE: Box only implements Error when E: Error + Sized, which means we can't pass a - // Box to request_value. - //assert_eq!(request_value::(&obj).unwrap(), "bye"); -} - -// Test the Error.provide and request mechanisms with a concrete object. -#[test] -fn test_error_generic_member_access_concrete() { - let obj = SomeConcreteType { some_string: "hello".to_owned() }; - - assert_eq!(request_ref::(&obj).unwrap(), "hello"); - assert_eq!(request_value::(&obj).unwrap(), "bye"); - assert_eq!(request_value::(&obj), None); -} diff --git a/library/core/tests/ffi.rs b/library/core/tests/ffi.rs deleted file mode 100644 index 2b33fbd95f0..00000000000 --- a/library/core/tests/ffi.rs +++ /dev/null @@ -1 +0,0 @@ -mod cstr; diff --git a/library/core/tests/ffi/cstr.rs b/library/core/tests/ffi/cstr.rs deleted file mode 100644 index 9bf4c21a9ab..00000000000 --- a/library/core/tests/ffi/cstr.rs +++ /dev/null @@ -1,15 +0,0 @@ -use core::ffi::CStr; - -#[test] -fn compares_as_u8s() { - let a: &CStr = c"Hello!"; // Starts with ascii - let a_bytes: &[u8] = a.to_bytes(); - assert!((..0b1000_0000).contains(&a_bytes[0])); - - let b: &CStr = c"こんにちは!"; // Starts with non ascii - let b_bytes: &[u8] = b.to_bytes(); - assert!((0b1000_0000..).contains(&b_bytes[0])); - - assert_eq!(Ord::cmp(a, b), Ord::cmp(a_bytes, b_bytes)); - assert_eq!(PartialOrd::partial_cmp(a, b), PartialOrd::partial_cmp(a_bytes, b_bytes)); -} diff --git a/library/core/tests/fmt/builders.rs b/library/core/tests/fmt/builders.rs deleted file mode 100644 index ba4801f5912..00000000000 --- a/library/core/tests/fmt/builders.rs +++ /dev/null @@ -1,1044 +0,0 @@ -mod debug_struct { - use std::fmt; - - #[test] - fn test_empty() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Foo").finish() - } - } - - assert_eq!("Foo", format!("{Foo:?}")); - assert_eq!("Foo", format!("{Foo:#?}")); - } - - #[test] - fn test_single() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Foo").field("bar", &true).finish() - } - } - - assert_eq!("Foo { bar: true }", format!("{Foo:?}")); - assert_eq!( - "Foo { - bar: true, -}", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_multiple() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Foo") - .field("bar", &true) - .field("baz", &format_args!("{}/{}", 10, 20)) - .finish() - } - } - - assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{Foo:?}")); - assert_eq!( - "Foo { - bar: true, - baz: 10/20, -}", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_nested() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Foo") - .field("bar", &true) - .field("baz", &format_args!("{}/{}", 10, 20)) - .finish() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Bar").field("foo", &Foo).field("hello", &"world").finish() - } - } - - assert_eq!( - r#"Bar { foo: Foo { bar: true, baz: 10/20 }, hello: "world" }"#, - format!("{Bar:?}") - ); - assert_eq!( - r#"Bar { - foo: Foo { - bar: true, - baz: 10/20, - }, - hello: "world", -}"#, - format!("{Bar:#?}") - ); - } - - #[test] - fn test_empty_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Foo").finish_non_exhaustive() - } - } - - assert_eq!("Foo { .. }", format!("{Foo:?}")); - assert_eq!("Foo { .. }", format!("{Foo:#?}")); - } - - #[test] - fn test_multiple_and_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Foo") - .field("bar", &true) - .field("baz", &format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{Foo:?}")); - assert_eq!( - "Foo { - bar: true, - baz: 10/20, - .. -}", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_nested_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Foo") - .field("bar", &true) - .field("baz", &format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Bar") - .field("foo", &Foo) - .field("hello", &"world") - .finish_non_exhaustive() - } - } - - assert_eq!( - r#"Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: "world", .. }"#, - format!("{Bar:?}") - ); - assert_eq!( - r#"Bar { - foo: Foo { - bar: true, - baz: 10/20, - .. - }, - hello: "world", - .. -}"#, - format!("{Bar:#?}") - ); - } -} - -mod debug_tuple { - use std::fmt; - - #[test] - fn test_empty() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Foo").finish() - } - } - - assert_eq!("Foo", format!("{Foo:?}")); - assert_eq!("Foo", format!("{Foo:#?}")); - } - - #[test] - fn test_single() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Foo").field(&true).finish() - } - } - - assert_eq!("Foo(true)", format!("{Foo:?}")); - assert_eq!( - "Foo( - true, -)", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_multiple() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Foo").field(&true).field(&format_args!("{}/{}", 10, 20)).finish() - } - } - - assert_eq!("Foo(true, 10/20)", format!("{Foo:?}")); - assert_eq!( - "Foo( - true, - 10/20, -)", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_nested() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Foo").field(&true).field(&format_args!("{}/{}", 10, 20)).finish() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Bar").field(&Foo).field(&"world").finish() - } - } - - assert_eq!(r#"Bar(Foo(true, 10/20), "world")"#, format!("{Bar:?}")); - assert_eq!( - r#"Bar( - Foo( - true, - 10/20, - ), - "world", -)"#, - format!("{Bar:#?}") - ); - } - - #[test] - fn test_empty_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Foo").finish_non_exhaustive() - } - } - - assert_eq!("Foo(..)", format!("{Foo:?}")); - assert_eq!("Foo(..)", format!("{Foo:#?}")); - } - - #[test] - fn test_multiple_and_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Foo") - .field(&true) - .field(&format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - assert_eq!("Foo(true, 10/20, ..)", format!("{Foo:?}")); - assert_eq!( - "Foo( - true, - 10/20, - .. -)", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_nested_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Foo") - .field(&true) - .field(&format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_tuple("Bar").field(&Foo).field(&"world").finish_non_exhaustive() - } - } - - assert_eq!(r#"Bar(Foo(true, 10/20, ..), "world", ..)"#, format!("{Bar:?}")); - assert_eq!( - r#"Bar( - Foo( - true, - 10/20, - .. - ), - "world", - .. -)"#, - format!("{Bar:#?}") - ); - } -} - -mod debug_map { - use std::fmt; - - #[test] - fn test_empty() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().finish() - } - } - - assert_eq!("{}", format!("{Foo:?}")); - assert_eq!("{}", format!("{Foo:#?}")); - } - - #[test] - fn test_single() { - struct Entry; - - impl fmt::Debug for Entry { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().entry(&"bar", &true).finish() - } - } - - struct KeyValue; - - impl fmt::Debug for KeyValue { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().key(&"bar").value(&true).finish() - } - } - - assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}")); - assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}")); - - assert_eq!(r#"{"bar": true}"#, format!("{Entry:?}")); - assert_eq!( - r#"{ - "bar": true, -}"#, - format!("{Entry:#?}") - ); - } - - #[test] - fn test_multiple() { - struct Entry; - - impl fmt::Debug for Entry { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map() - .entry(&"bar", &true) - .entry(&10, &format_args!("{}/{}", 10, 20)) - .finish() - } - } - - struct KeyValue; - - impl fmt::Debug for KeyValue { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map() - .key(&"bar") - .value(&true) - .key(&10) - .value(&format_args!("{}/{}", 10, 20)) - .finish() - } - } - - assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}")); - assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}")); - - assert_eq!(r#"{"bar": true, 10: 10/20}"#, format!("{Entry:?}")); - assert_eq!( - r#"{ - "bar": true, - 10: 10/20, -}"#, - format!("{Entry:#?}") - ); - } - - #[test] - fn test_nested() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map() - .entry(&"bar", &true) - .entry(&10, &format_args!("{}/{}", 10, 20)) - .finish() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().entry(&"foo", &Foo).entry(&Foo, &"world").finish() - } - } - - assert_eq!( - r#"{"foo": {"bar": true, 10: 10/20}, {"bar": true, 10: 10/20}: "world"}"#, - format!("{Bar:?}") - ); - assert_eq!( - r#"{ - "foo": { - "bar": true, - 10: 10/20, - }, - { - "bar": true, - 10: 10/20, - }: "world", -}"#, - format!("{Bar:#?}") - ); - } - - #[test] - fn test_entry_err() { - // Ensure errors in a map entry don't trigger panics (#65231) - use std::fmt::Write; - - struct ErrorFmt; - - impl fmt::Debug for ErrorFmt { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - Err(fmt::Error) - } - } - - struct KeyValue(usize, K, V); - - impl fmt::Debug for KeyValue - where - K: fmt::Debug, - V: fmt::Debug, - { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut map = fmt.debug_map(); - - for _ in 0..self.0 { - map.entry(&self.1, &self.2); - } - - map.finish() - } - } - - let mut buf = String::new(); - - assert!(write!(&mut buf, "{:?}", KeyValue(1, ErrorFmt, "bar")).is_err()); - assert!(write!(&mut buf, "{:?}", KeyValue(1, "foo", ErrorFmt)).is_err()); - - assert!(write!(&mut buf, "{:?}", KeyValue(2, ErrorFmt, "bar")).is_err()); - assert!(write!(&mut buf, "{:?}", KeyValue(2, "foo", ErrorFmt)).is_err()); - } - - #[test] - #[should_panic] - fn test_invalid_key_when_entry_is_incomplete() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().key(&"bar").key(&"invalid").finish() - } - } - - let _ = format!("{Foo:?}"); - } - - #[test] - #[should_panic] - fn test_invalid_finish_incomplete_entry() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().key(&"bar").finish() - } - } - - let _ = format!("{Foo:?}"); - } - - #[test] - #[should_panic] - fn test_invalid_value_before_key() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().value(&"invalid").key(&"bar").finish() - } - } - - let _ = format!("{Foo:?}"); - } - - #[test] - fn test_empty_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().finish_non_exhaustive() - } - } - - assert_eq!("{..}", format!("{Foo:?}")); - assert_eq!("{..}", format!("{Foo:#?}")); - } - - #[test] - fn test_multiple_and_non_exhaustive() { - struct Entry; - - impl fmt::Debug for Entry { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map() - .entry(&"bar", &true) - .entry(&10, &format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - struct KeyValue; - - impl fmt::Debug for KeyValue { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map() - .key(&"bar") - .value(&true) - .key(&10) - .value(&format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}")); - assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}")); - - assert_eq!(r#"{"bar": true, 10: 10/20, ..}"#, format!("{Entry:?}")); - assert_eq!( - r#"{ - "bar": true, - 10: 10/20, - .. -}"#, - format!("{Entry:#?}") - ); - } - - #[test] - fn test_nested_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map() - .entry(&"bar", &true) - .entry(&10, &format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().entry(&"foo", &Foo).entry(&Foo, &"world").finish_non_exhaustive() - } - } - - assert_eq!( - r#"{"foo": {"bar": true, 10: 10/20, ..}, {"bar": true, 10: 10/20, ..}: "world", ..}"#, - format!("{Bar:?}") - ); - assert_eq!( - r#"{ - "foo": { - "bar": true, - 10: 10/20, - .. - }, - { - "bar": true, - 10: 10/20, - .. - }: "world", - .. -}"#, - format!("{Bar:#?}") - ); - } -} - -mod debug_set { - use std::fmt; - - #[test] - fn test_empty() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_set().finish() - } - } - - assert_eq!("{}", format!("{Foo:?}")); - assert_eq!("{}", format!("{Foo:#?}")); - } - - #[test] - fn test_single() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_set().entry(&true).finish() - } - } - - assert_eq!("{true}", format!("{Foo:?}")); - assert_eq!( - "{ - true, -}", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_multiple() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_set().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish() - } - } - - assert_eq!("{true, 10/20}", format!("{Foo:?}")); - assert_eq!( - "{ - true, - 10/20, -}", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_nested() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_set().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_set().entry(&Foo).entry(&"world").finish() - } - } - - assert_eq!(r#"{{true, 10/20}, "world"}"#, format!("{Bar:?}")); - assert_eq!( - r#"{ - { - true, - 10/20, - }, - "world", -}"#, - format!("{Bar:#?}") - ); - } - - #[test] - fn test_empty_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_set().finish_non_exhaustive() - } - } - - assert_eq!("{..}", format!("{Foo:?}")); - assert_eq!("{..}", format!("{Foo:#?}")); - } - - #[test] - fn test_multiple_and_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_set() - .entry(&true) - .entry(&format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - assert_eq!("{true, 10/20, ..}", format!("{Foo:?}")); - assert_eq!( - "{ - true, - 10/20, - .. -}", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_nested_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_set() - .entry(&true) - .entry(&format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_set().entry(&Foo).entry(&"world").finish_non_exhaustive() - } - } - - assert_eq!(r#"{{true, 10/20, ..}, "world", ..}"#, format!("{Bar:?}")); - assert_eq!( - r#"{ - { - true, - 10/20, - .. - }, - "world", - .. -}"#, - format!("{Bar:#?}") - ); - } -} - -mod debug_list { - use std::fmt; - - #[test] - fn test_empty() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_list().finish() - } - } - - assert_eq!("[]", format!("{Foo:?}")); - assert_eq!("[]", format!("{Foo:#?}")); - } - - #[test] - fn test_single() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_list().entry(&true).finish() - } - } - - assert_eq!("[true]", format!("{Foo:?}")); - assert_eq!( - "[ - true, -]", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_multiple() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_list().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish() - } - } - - assert_eq!("[true, 10/20]", format!("{Foo:?}")); - assert_eq!( - "[ - true, - 10/20, -]", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_nested() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_list().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_list().entry(&Foo).entry(&"world").finish() - } - } - - assert_eq!(r#"[[true, 10/20], "world"]"#, format!("{Bar:?}")); - assert_eq!( - r#"[ - [ - true, - 10/20, - ], - "world", -]"#, - format!("{Bar:#?}") - ); - } - - #[test] - fn test_empty_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_list().finish_non_exhaustive() - } - } - - assert_eq!("[..]", format!("{Foo:?}")); - assert_eq!("[..]", format!("{Foo:#?}")); - } - - #[test] - fn test_multiple_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_list() - .entry(&true) - .entry(&format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - assert_eq!("[true, 10/20, ..]", format!("{Foo:?}")); - assert_eq!( - "[ - true, - 10/20, - .. -]", - format!("{Foo:#?}") - ); - } - - #[test] - fn test_nested_non_exhaustive() { - struct Foo; - - impl fmt::Debug for Foo { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_list() - .entry(&true) - .entry(&format_args!("{}/{}", 10, 20)) - .finish_non_exhaustive() - } - } - - struct Bar; - - impl fmt::Debug for Bar { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_list().entry(&Foo).entry(&"world").finish_non_exhaustive() - } - } - - assert_eq!(r#"[[true, 10/20, ..], "world", ..]"#, format!("{Bar:?}")); - assert_eq!( - r#"[ - [ - true, - 10/20, - .. - ], - "world", - .. -]"#, - format!("{Bar:#?}") - ); - } -} - -#[test] -fn test_formatting_parameters_are_forwarded() { - use std::collections::{BTreeMap, BTreeSet}; - #[derive(Debug)] - #[allow(dead_code)] - struct Foo { - bar: u32, - baz: u32, - } - let struct_ = Foo { bar: 1024, baz: 7 }; - let tuple = (1024, 7); - let list = [1024, 7]; - let mut map = BTreeMap::new(); - map.insert("bar", 1024); - map.insert("baz", 7); - let mut set = BTreeSet::new(); - set.insert(1024); - set.insert(7); - - assert_eq!(format!("{struct_:03?}"), "Foo { bar: 1024, baz: 007 }"); - assert_eq!(format!("{tuple:03?}"), "(1024, 007)"); - assert_eq!(format!("{list:03?}"), "[1024, 007]"); - assert_eq!(format!("{map:03?}"), r#"{"bar": 1024, "baz": 007}"#); - assert_eq!(format!("{set:03?}"), "{007, 1024}"); - assert_eq!( - format!("{struct_:#03?}"), - " -Foo { - bar: 1024, - baz: 007, -} - " - .trim() - ); - assert_eq!( - format!("{tuple:#03?}"), - " -( - 1024, - 007, -) - " - .trim() - ); - assert_eq!( - format!("{list:#03?}"), - " -[ - 1024, - 007, -] - " - .trim() - ); - assert_eq!( - format!("{map:#03?}"), - r#" -{ - "bar": 1024, - "baz": 007, -} - "# - .trim() - ); - assert_eq!( - format!("{set:#03?}"), - " -{ - 007, - 1024, -} - " - .trim() - ); -} diff --git a/library/core/tests/fmt/float.rs b/library/core/tests/fmt/float.rs deleted file mode 100644 index 003782f34dc..00000000000 --- a/library/core/tests/fmt/float.rs +++ /dev/null @@ -1,175 +0,0 @@ -#[test] -fn test_format_f64() { - assert_eq!("1", format!("{:.0}", 1.0f64)); - assert_eq!("9", format!("{:.0}", 9.4f64)); - assert_eq!("10", format!("{:.0}", 9.9f64)); - assert_eq!("9.8", format!("{:.1}", 9.849f64)); - assert_eq!("9.9", format!("{:.1}", 9.851f64)); - assert_eq!("0", format!("{:.0}", 0.5f64)); - assert_eq!("1.23456789e6", format!("{:e}", 1234567.89f64)); - assert_eq!("1.23456789e3", format!("{:e}", 1234.56789f64)); - assert_eq!("1.23456789E6", format!("{:E}", 1234567.89f64)); - assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64)); - assert_eq!("0.0", format!("{:?}", 0.0f64)); - assert_eq!("1.01", format!("{:?}", 1.01f64)); - - let high_cutoff = 1e16_f64; - assert_eq!("1e16", format!("{:?}", high_cutoff)); - assert_eq!("-1e16", format!("{:?}", -high_cutoff)); - assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f64::EPSILON)))); - assert_eq!("-3.0", format!("{:?}", -3f64)); - assert_eq!("0.0001", format!("{:?}", 0.0001f64)); - assert_eq!("9e-5", format!("{:?}", 0.00009f64)); - assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f64)); - assert_eq!("1234.6", format!("{:.1?}", 1234.56789f64)); -} - -#[test] -fn test_format_f64_rounds_ties_to_even() { - assert_eq!("0", format!("{:.0}", 0.5f64)); - assert_eq!("2", format!("{:.0}", 1.5f64)); - assert_eq!("2", format!("{:.0}", 2.5f64)); - assert_eq!("4", format!("{:.0}", 3.5f64)); - assert_eq!("4", format!("{:.0}", 4.5f64)); - assert_eq!("6", format!("{:.0}", 5.5f64)); - assert_eq!("128", format!("{:.0}", 127.5f64)); - assert_eq!("128", format!("{:.0}", 128.5f64)); - assert_eq!("0.2", format!("{:.1}", 0.25f64)); - assert_eq!("0.8", format!("{:.1}", 0.75f64)); - assert_eq!("0.12", format!("{:.2}", 0.125f64)); - assert_eq!("0.88", format!("{:.2}", 0.875f64)); - assert_eq!("0.062", format!("{:.3}", 0.062f64)); - assert_eq!("-0", format!("{:.0}", -0.5f64)); - assert_eq!("-2", format!("{:.0}", -1.5f64)); - assert_eq!("-2", format!("{:.0}", -2.5f64)); - assert_eq!("-4", format!("{:.0}", -3.5f64)); - assert_eq!("-4", format!("{:.0}", -4.5f64)); - assert_eq!("-6", format!("{:.0}", -5.5f64)); - assert_eq!("-128", format!("{:.0}", -127.5f64)); - assert_eq!("-128", format!("{:.0}", -128.5f64)); - assert_eq!("-0.2", format!("{:.1}", -0.25f64)); - assert_eq!("-0.8", format!("{:.1}", -0.75f64)); - assert_eq!("-0.12", format!("{:.2}", -0.125f64)); - assert_eq!("-0.88", format!("{:.2}", -0.875f64)); - assert_eq!("-0.062", format!("{:.3}", -0.062f64)); - - assert_eq!("2e0", format!("{:.0e}", 1.5f64)); - assert_eq!("2e0", format!("{:.0e}", 2.5f64)); - assert_eq!("4e0", format!("{:.0e}", 3.5f64)); - assert_eq!("4e0", format!("{:.0e}", 4.5f64)); - assert_eq!("6e0", format!("{:.0e}", 5.5f64)); - assert_eq!("1.28e2", format!("{:.2e}", 127.5f64)); - assert_eq!("1.28e2", format!("{:.2e}", 128.5f64)); - assert_eq!("-2e0", format!("{:.0e}", -1.5f64)); - assert_eq!("-2e0", format!("{:.0e}", -2.5f64)); - assert_eq!("-4e0", format!("{:.0e}", -3.5f64)); - assert_eq!("-4e0", format!("{:.0e}", -4.5f64)); - assert_eq!("-6e0", format!("{:.0e}", -5.5f64)); - assert_eq!("-1.28e2", format!("{:.2e}", -127.5f64)); - assert_eq!("-1.28e2", format!("{:.2e}", -128.5f64)); - - assert_eq!("2E0", format!("{:.0E}", 1.5f64)); - assert_eq!("2E0", format!("{:.0E}", 2.5f64)); - assert_eq!("4E0", format!("{:.0E}", 3.5f64)); - assert_eq!("4E0", format!("{:.0E}", 4.5f64)); - assert_eq!("6E0", format!("{:.0E}", 5.5f64)); - assert_eq!("1.28E2", format!("{:.2E}", 127.5f64)); - assert_eq!("1.28E2", format!("{:.2E}", 128.5f64)); - assert_eq!("-2E0", format!("{:.0E}", -1.5f64)); - assert_eq!("-2E0", format!("{:.0E}", -2.5f64)); - assert_eq!("-4E0", format!("{:.0E}", -3.5f64)); - assert_eq!("-4E0", format!("{:.0E}", -4.5f64)); - assert_eq!("-6E0", format!("{:.0E}", -5.5f64)); - assert_eq!("-1.28E2", format!("{:.2E}", -127.5f64)); - assert_eq!("-1.28E2", format!("{:.2E}", -128.5f64)); -} - -#[test] -fn test_format_f32() { - assert_eq!("1", format!("{:.0}", 1.0f32)); - assert_eq!("9", format!("{:.0}", 9.4f32)); - assert_eq!("10", format!("{:.0}", 9.9f32)); - assert_eq!("9.8", format!("{:.1}", 9.849f32)); - assert_eq!("9.9", format!("{:.1}", 9.851f32)); - assert_eq!("0", format!("{:.0}", 0.5f32)); - assert_eq!("1.2345679e6", format!("{:e}", 1234567.89f32)); - assert_eq!("1.2345679e3", format!("{:e}", 1234.56789f32)); - assert_eq!("1.2345679E6", format!("{:E}", 1234567.89f32)); - assert_eq!("1.2345679E3", format!("{:E}", 1234.56789f32)); - assert_eq!("0.0", format!("{:?}", 0.0f32)); - assert_eq!("1.01", format!("{:?}", 1.01f32)); - - let high_cutoff = 1e16_f32; - assert_eq!("1e16", format!("{:?}", high_cutoff)); - assert_eq!("-1e16", format!("{:?}", -high_cutoff)); - assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f32::EPSILON)))); - assert_eq!("-3.0", format!("{:?}", -3f32)); - assert_eq!("0.0001", format!("{:?}", 0.0001f32)); - assert_eq!("9e-5", format!("{:?}", 0.00009f32)); - assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f32)); - assert_eq!("1234.6", format!("{:.1?}", 1234.56789f32)); -} - -#[test] -fn test_format_f32_rounds_ties_to_even() { - assert_eq!("0", format!("{:.0}", 0.5f32)); - assert_eq!("2", format!("{:.0}", 1.5f32)); - assert_eq!("2", format!("{:.0}", 2.5f32)); - assert_eq!("4", format!("{:.0}", 3.5f32)); - assert_eq!("4", format!("{:.0}", 4.5f32)); - assert_eq!("6", format!("{:.0}", 5.5f32)); - assert_eq!("128", format!("{:.0}", 127.5f32)); - assert_eq!("128", format!("{:.0}", 128.5f32)); - assert_eq!("0.2", format!("{:.1}", 0.25f32)); - assert_eq!("0.8", format!("{:.1}", 0.75f32)); - assert_eq!("0.12", format!("{:.2}", 0.125f32)); - assert_eq!("0.88", format!("{:.2}", 0.875f32)); - assert_eq!("0.062", format!("{:.3}", 0.062f32)); - assert_eq!("-0", format!("{:.0}", -0.5f32)); - assert_eq!("-2", format!("{:.0}", -1.5f32)); - assert_eq!("-2", format!("{:.0}", -2.5f32)); - assert_eq!("-4", format!("{:.0}", -3.5f32)); - assert_eq!("-4", format!("{:.0}", -4.5f32)); - assert_eq!("-6", format!("{:.0}", -5.5f32)); - assert_eq!("-128", format!("{:.0}", -127.5f32)); - assert_eq!("-128", format!("{:.0}", -128.5f32)); - assert_eq!("-0.2", format!("{:.1}", -0.25f32)); - assert_eq!("-0.8", format!("{:.1}", -0.75f32)); - assert_eq!("-0.12", format!("{:.2}", -0.125f32)); - assert_eq!("-0.88", format!("{:.2}", -0.875f32)); - assert_eq!("-0.062", format!("{:.3}", -0.062f32)); - - assert_eq!("2e0", format!("{:.0e}", 1.5f32)); - assert_eq!("2e0", format!("{:.0e}", 2.5f32)); - assert_eq!("4e0", format!("{:.0e}", 3.5f32)); - assert_eq!("4e0", format!("{:.0e}", 4.5f32)); - assert_eq!("6e0", format!("{:.0e}", 5.5f32)); - assert_eq!("1.28e2", format!("{:.2e}", 127.5f32)); - assert_eq!("1.28e2", format!("{:.2e}", 128.5f32)); - assert_eq!("-2e0", format!("{:.0e}", -1.5f32)); - assert_eq!("-2e0", format!("{:.0e}", -2.5f32)); - assert_eq!("-4e0", format!("{:.0e}", -3.5f32)); - assert_eq!("-4e0", format!("{:.0e}", -4.5f32)); - assert_eq!("-6e0", format!("{:.0e}", -5.5f32)); - assert_eq!("-1.28e2", format!("{:.2e}", -127.5f32)); - assert_eq!("-1.28e2", format!("{:.2e}", -128.5f32)); - - assert_eq!("2E0", format!("{:.0E}", 1.5f32)); - assert_eq!("2E0", format!("{:.0E}", 2.5f32)); - assert_eq!("4E0", format!("{:.0E}", 3.5f32)); - assert_eq!("4E0", format!("{:.0E}", 4.5f32)); - assert_eq!("6E0", format!("{:.0E}", 5.5f32)); - assert_eq!("1.28E2", format!("{:.2E}", 127.5f32)); - assert_eq!("1.28E2", format!("{:.2E}", 128.5f32)); - assert_eq!("-2E0", format!("{:.0E}", -1.5f32)); - assert_eq!("-2E0", format!("{:.0E}", -2.5f32)); - assert_eq!("-4E0", format!("{:.0E}", -3.5f32)); - assert_eq!("-4E0", format!("{:.0E}", -4.5f32)); - assert_eq!("-6E0", format!("{:.0E}", -5.5f32)); - assert_eq!("-1.28E2", format!("{:.2E}", -127.5f32)); - assert_eq!("-1.28E2", format!("{:.2E}", -128.5f32)); -} - -fn is_exponential(s: &str) -> bool { - s.contains("e") || s.contains("E") -} diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs deleted file mode 100644 index 025c69c4f62..00000000000 --- a/library/core/tests/fmt/mod.rs +++ /dev/null @@ -1,82 +0,0 @@ -mod builders; -mod float; -mod num; - -#[test] -fn test_format_flags() { - // No residual flags left by pointer formatting - let p = "".as_ptr(); - assert_eq!(format!("{:p} {:x}", p, 16), format!("{p:p} 10")); - - assert_eq!(format!("{: >3}", 'a'), " a"); -} - -#[test] -fn test_pointer_formats_data_pointer() { - let b: &[u8] = b""; - let s: &str = ""; - assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr())); - assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr())); -} - -#[test] -fn test_estimated_capacity() { - assert_eq!(format_args!("").estimated_capacity(), 0); - assert_eq!(format_args!("{}", { "" }).estimated_capacity(), 0); - assert_eq!(format_args!("Hello").estimated_capacity(), 5); - assert_eq!(format_args!("Hello, {}!", { "" }).estimated_capacity(), 16); - assert_eq!(format_args!("{}, hello!", { "World" }).estimated_capacity(), 0); - assert_eq!(format_args!("{}. 16-bytes piece", { "World" }).estimated_capacity(), 32); -} - -#[test] -fn pad_integral_resets() { - struct Bar; - - impl core::fmt::Display for Bar { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - "1".fmt(f)?; - f.pad_integral(true, "", "5")?; - "1".fmt(f) - } - } - - assert_eq!(format!("{Bar:<03}"), "1 0051 "); -} - -#[test] -fn test_maybe_uninit_short() { - // Ensure that the trimmed `MaybeUninit` Debug implementation doesn't break - let x = core::mem::MaybeUninit::new(0u32); - assert_eq!(format!("{x:?}"), "MaybeUninit"); -} - -#[test] -fn formatting_options_ctor() { - use core::fmt::FormattingOptions; - assert_eq!(FormattingOptions::new(), FormattingOptions::default()); -} - -#[test] -fn formatting_options_flags() { - use core::fmt::*; - for sign in [None, Some(Sign::Plus), Some(Sign::Minus)] { - for alternate in [true, false] { - for sign_aware_zero_pad in [true, false] { - for debug_as_hex in [None, Some(DebugAsHex::Lower), Some(DebugAsHex::Upper)] { - let mut formatting_options = FormattingOptions::new(); - formatting_options - .sign(sign) - .sign_aware_zero_pad(sign_aware_zero_pad) - .alternate(alternate) - .debug_as_hex(debug_as_hex); - - assert_eq!(formatting_options.get_sign(), sign); - assert_eq!(formatting_options.get_alternate(), alternate); - assert_eq!(formatting_options.get_sign_aware_zero_pad(), sign_aware_zero_pad); - assert_eq!(formatting_options.get_debug_as_hex(), debug_as_hex); - } - } - } - } -} diff --git a/library/core/tests/fmt/num.rs b/library/core/tests/fmt/num.rs deleted file mode 100644 index bc387a46ea7..00000000000 --- a/library/core/tests/fmt/num.rs +++ /dev/null @@ -1,240 +0,0 @@ -#[test] -fn test_format_int() { - // Formatting integers should select the right implementation based off - // the type of the argument. Also, hex/octal/binary should be defined - // for integers, but they shouldn't emit the negative sign. - assert_eq!(format!("{}", 1isize), "1"); - assert_eq!(format!("{}", 1i8), "1"); - assert_eq!(format!("{}", 1i16), "1"); - assert_eq!(format!("{}", 1i32), "1"); - assert_eq!(format!("{}", 1i64), "1"); - assert_eq!(format!("{}", -1isize), "-1"); - assert_eq!(format!("{}", -1i8), "-1"); - assert_eq!(format!("{}", -1i16), "-1"); - assert_eq!(format!("{}", -1i32), "-1"); - assert_eq!(format!("{}", -1i64), "-1"); - assert_eq!(format!("{:?}", 1isize), "1"); - assert_eq!(format!("{:?}", 1i8), "1"); - assert_eq!(format!("{:?}", 1i16), "1"); - assert_eq!(format!("{:?}", 1i32), "1"); - assert_eq!(format!("{:?}", 1i64), "1"); - assert_eq!(format!("{:b}", 1isize), "1"); - assert_eq!(format!("{:b}", 1i8), "1"); - assert_eq!(format!("{:b}", 1i16), "1"); - assert_eq!(format!("{:b}", 1i32), "1"); - assert_eq!(format!("{:b}", 1i64), "1"); - assert_eq!(format!("{:x}", 1isize), "1"); - assert_eq!(format!("{:x}", 1i8), "1"); - assert_eq!(format!("{:x}", 1i16), "1"); - assert_eq!(format!("{:x}", 1i32), "1"); - assert_eq!(format!("{:x}", 1i64), "1"); - assert_eq!(format!("{:X}", 1isize), "1"); - assert_eq!(format!("{:X}", 1i8), "1"); - assert_eq!(format!("{:X}", 1i16), "1"); - assert_eq!(format!("{:X}", 1i32), "1"); - assert_eq!(format!("{:X}", 1i64), "1"); - assert_eq!(format!("{:o}", 1isize), "1"); - assert_eq!(format!("{:o}", 1i8), "1"); - assert_eq!(format!("{:o}", 1i16), "1"); - assert_eq!(format!("{:o}", 1i32), "1"); - assert_eq!(format!("{:o}", 1i64), "1"); - assert_eq!(format!("{:e}", 1isize), "1e0"); - assert_eq!(format!("{:e}", 1i8), "1e0"); - assert_eq!(format!("{:e}", 1i16), "1e0"); - assert_eq!(format!("{:e}", 1i32), "1e0"); - assert_eq!(format!("{:e}", 1i64), "1e0"); - assert_eq!(format!("{:E}", 1isize), "1E0"); - assert_eq!(format!("{:E}", 1i8), "1E0"); - assert_eq!(format!("{:E}", 1i16), "1E0"); - assert_eq!(format!("{:E}", 1i32), "1E0"); - assert_eq!(format!("{:E}", 1i64), "1E0"); - - assert_eq!(format!("{}", 1usize), "1"); - assert_eq!(format!("{}", 1u8), "1"); - assert_eq!(format!("{}", 1u16), "1"); - assert_eq!(format!("{}", 1u32), "1"); - assert_eq!(format!("{}", 1u64), "1"); - assert_eq!(format!("{:?}", 1usize), "1"); - assert_eq!(format!("{:?}", 1u8), "1"); - assert_eq!(format!("{:?}", 1u16), "1"); - assert_eq!(format!("{:?}", 1u32), "1"); - assert_eq!(format!("{:?}", 1u64), "1"); - assert_eq!(format!("{:b}", 1usize), "1"); - assert_eq!(format!("{:b}", 1u8), "1"); - assert_eq!(format!("{:b}", 1u16), "1"); - assert_eq!(format!("{:b}", 1u32), "1"); - assert_eq!(format!("{:b}", 1u64), "1"); - assert_eq!(format!("{:x}", 1usize), "1"); - assert_eq!(format!("{:x}", 1u8), "1"); - assert_eq!(format!("{:x}", 1u16), "1"); - assert_eq!(format!("{:x}", 1u32), "1"); - assert_eq!(format!("{:x}", 1u64), "1"); - assert_eq!(format!("{:X}", 1usize), "1"); - assert_eq!(format!("{:X}", 1u8), "1"); - assert_eq!(format!("{:X}", 1u16), "1"); - assert_eq!(format!("{:X}", 1u32), "1"); - assert_eq!(format!("{:X}", 1u64), "1"); - assert_eq!(format!("{:o}", 1usize), "1"); - assert_eq!(format!("{:o}", 1u8), "1"); - assert_eq!(format!("{:o}", 1u16), "1"); - assert_eq!(format!("{:o}", 1u32), "1"); - assert_eq!(format!("{:o}", 1u64), "1"); - assert_eq!(format!("{:e}", 1u8), "1e0"); - assert_eq!(format!("{:e}", 1u16), "1e0"); - assert_eq!(format!("{:e}", 1u32), "1e0"); - assert_eq!(format!("{:e}", 1u64), "1e0"); - assert_eq!(format!("{:E}", 1u8), "1E0"); - assert_eq!(format!("{:E}", 1u16), "1E0"); - assert_eq!(format!("{:E}", 1u32), "1E0"); - assert_eq!(format!("{:E}", 1u64), "1E0"); - - // Test a larger number - assert_eq!(format!("{:b}", 55), "110111"); - assert_eq!(format!("{:o}", 55), "67"); - assert_eq!(format!("{}", 55), "55"); - assert_eq!(format!("{:x}", 55), "37"); - assert_eq!(format!("{:X}", 55), "37"); - assert_eq!(format!("{:e}", 55), "5.5e1"); - assert_eq!(format!("{:E}", 55), "5.5E1"); - assert_eq!(format!("{:e}", 10000000000u64), "1e10"); - assert_eq!(format!("{:E}", 10000000000u64), "1E10"); - assert_eq!(format!("{:e}", 10000000001u64), "1.0000000001e10"); - assert_eq!(format!("{:E}", 10000000001u64), "1.0000000001E10"); -} - -#[test] -fn test_format_int_exp_limits() { - assert_eq!(format!("{:e}", i8::MIN), "-1.28e2"); - assert_eq!(format!("{:e}", i8::MAX), "1.27e2"); - assert_eq!(format!("{:e}", i16::MIN), "-3.2768e4"); - assert_eq!(format!("{:e}", i16::MAX), "3.2767e4"); - assert_eq!(format!("{:e}", i32::MIN), "-2.147483648e9"); - assert_eq!(format!("{:e}", i32::MAX), "2.147483647e9"); - assert_eq!(format!("{:e}", i64::MIN), "-9.223372036854775808e18"); - assert_eq!(format!("{:e}", i64::MAX), "9.223372036854775807e18"); - assert_eq!(format!("{:e}", i128::MIN), "-1.70141183460469231731687303715884105728e38"); - assert_eq!(format!("{:e}", i128::MAX), "1.70141183460469231731687303715884105727e38"); - - assert_eq!(format!("{:e}", u8::MAX), "2.55e2"); - assert_eq!(format!("{:e}", u16::MAX), "6.5535e4"); - assert_eq!(format!("{:e}", u32::MAX), "4.294967295e9"); - assert_eq!(format!("{:e}", u64::MAX), "1.8446744073709551615e19"); - assert_eq!(format!("{:e}", u128::MAX), "3.40282366920938463463374607431768211455e38"); -} - -#[test] -fn test_format_int_exp_precision() { - //test that float and integer match - let big_int: u32 = 314_159_265; - assert_eq!(format!("{big_int:.1e}"), format!("{:.1e}", f64::from(big_int))); - - // test adding precision - assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2"); - assert_eq!(format!("{:.10e}", i16::MIN), "-3.2768000000e4"); - assert_eq!(format!("{:.10e}", i32::MIN), "-2.1474836480e9"); - assert_eq!(format!("{:.20e}", i64::MIN), "-9.22337203685477580800e18"); - assert_eq!(format!("{:.40e}", i128::MIN), "-1.7014118346046923173168730371588410572800e38"); - - // test rounding - assert_eq!(format!("{:.1e}", i8::MIN), "-1.3e2"); - assert_eq!(format!("{:.1e}", i16::MIN), "-3.3e4"); - assert_eq!(format!("{:.1e}", i32::MIN), "-2.1e9"); - assert_eq!(format!("{:.1e}", i64::MIN), "-9.2e18"); - assert_eq!(format!("{:.1e}", i128::MIN), "-1.7e38"); - - // test huge precision - assert_eq!(format!("{:.1000e}", 1), format!("1.{}e0", "0".repeat(1000))); - //test zero precision - assert_eq!(format!("{:.0e}", 1), format!("1e0",)); - assert_eq!(format!("{:.0e}", 35), format!("4e1",)); - - // test padding with precision (and sign) - assert_eq!(format!("{:+10.3e}", 1), " +1.000e0"); - - // test precision remains correct when rounding to next power - #[cfg(miri)] // can't cover all of `i16` in Miri - let range = [i16::MIN, -1, 1, i16::MAX]; - #[cfg(not(miri))] - let range = i16::MIN..=i16::MAX; - for i in range { - for p in 0..=5 { - assert_eq!( - format!("{i:.p$e}"), - format!("{:.p$e}", f32::from(i)), - "integer {i} at precision {p}" - ); - } - } -} - -#[test] -fn test_format_int_zero() { - assert_eq!(format!("{}", 0), "0"); - assert_eq!(format!("{:?}", 0), "0"); - assert_eq!(format!("{:b}", 0), "0"); - assert_eq!(format!("{:o}", 0), "0"); - assert_eq!(format!("{:x}", 0), "0"); - assert_eq!(format!("{:X}", 0), "0"); - assert_eq!(format!("{:e}", 0), "0e0"); - assert_eq!(format!("{:E}", 0), "0E0"); - - assert_eq!(format!("{}", 0u32), "0"); - assert_eq!(format!("{:?}", 0u32), "0"); - assert_eq!(format!("{:b}", 0u32), "0"); - assert_eq!(format!("{:o}", 0u32), "0"); - assert_eq!(format!("{:x}", 0u32), "0"); - assert_eq!(format!("{:X}", 0u32), "0"); - assert_eq!(format!("{:e}", 0u32), "0e0"); - assert_eq!(format!("{:E}", 0u32), "0E0"); -} - -#[test] -fn test_format_int_flags() { - assert_eq!(format!("{:3}", 1), " 1"); - assert_eq!(format!("{:>3}", 1), " 1"); - assert_eq!(format!("{:>+3}", 1), " +1"); - assert_eq!(format!("{:<3}", 1), "1 "); - assert_eq!(format!("{:#}", 1), "1"); - assert_eq!(format!("{:#x}", 10), "0xa"); - assert_eq!(format!("{:#X}", 10), "0xA"); - assert_eq!(format!("{:#5x}", 10), " 0xa"); - assert_eq!(format!("{:#o}", 10), "0o12"); - assert_eq!(format!("{:08x}", 10), "0000000a"); - assert_eq!(format!("{:8x}", 10), " a"); - assert_eq!(format!("{:<8x}", 10), "a "); - assert_eq!(format!("{:>8x}", 10), " a"); - assert_eq!(format!("{:#08x}", 10), "0x00000a"); - assert_eq!(format!("{:08}", -10), "-0000010"); - assert_eq!(format!("{:x}", !0u8), "ff"); - assert_eq!(format!("{:X}", !0u8), "FF"); - assert_eq!(format!("{:b}", !0u8), "11111111"); - assert_eq!(format!("{:o}", !0u8), "377"); - assert_eq!(format!("{:#x}", !0u8), "0xff"); - assert_eq!(format!("{:#X}", !0u8), "0xFF"); - assert_eq!(format!("{:#b}", !0u8), "0b11111111"); - assert_eq!(format!("{:#o}", !0u8), "0o377"); -} - -#[test] -fn test_format_int_sign_padding() { - assert_eq!(format!("{:+5}", 1), " +1"); - assert_eq!(format!("{:+5}", -1), " -1"); - assert_eq!(format!("{:05}", 1), "00001"); - assert_eq!(format!("{:05}", -1), "-0001"); - assert_eq!(format!("{:+05}", 1), "+0001"); - assert_eq!(format!("{:+05}", -1), "-0001"); -} - -#[test] -fn test_format_int_twos_complement() { - assert_eq!(format!("{}", i8::MIN), "-128"); - assert_eq!(format!("{}", i16::MIN), "-32768"); - assert_eq!(format!("{}", i32::MIN), "-2147483648"); - assert_eq!(format!("{}", i64::MIN), "-9223372036854775808"); -} - -#[test] -fn test_format_debug_hex() { - assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]"); - assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]"); -} diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs deleted file mode 100644 index ebfe5a0a66d..00000000000 --- a/library/core/tests/future.rs +++ /dev/null @@ -1,127 +0,0 @@ -use std::future::{Future, join}; -use std::pin::Pin; -use std::sync::Arc; -use std::task::{Context, Poll, Wake}; -use std::thread; - -struct PollN { - val: usize, - polled: usize, - num: usize, -} - -impl Future for PollN { - type Output = usize; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.polled += 1; - - if self.polled == self.num { - return Poll::Ready(self.val); - } - - cx.waker().wake_by_ref(); - Poll::Pending - } -} - -fn poll_n(val: usize, num: usize) -> PollN { - PollN { val, num, polled: 0 } -} - -#[test] -fn test_join() { - block_on(async move { - let x = join!(async { 0 }).await; - assert_eq!(x, 0); - - let x = join!(async { 0 }, async { 1 }).await; - assert_eq!(x, (0, 1)); - - let x = join!(async { 0 }, async { 1 }, async { 2 }).await; - assert_eq!(x, (0, 1, 2)); - - let x = join!( - poll_n(0, 1), - poll_n(1, 5), - poll_n(2, 2), - poll_n(3, 1), - poll_n(4, 2), - poll_n(5, 3), - poll_n(6, 4), - poll_n(7, 1) - ) - .await; - assert_eq!(x, (0, 1, 2, 3, 4, 5, 6, 7)); - - let y = String::new(); - let x = join!(async { - println!("{y}"); - 1 - }) - .await; - assert_eq!(x, 1); - }); -} - -/// Tests that `join!(…)` behaves "like a function": evaluating its arguments -/// before applying any of its own logic. -/// -/// _e.g._, `join!(async_fn(&borrowed), …)` does not consume `borrowed`; -/// and `join!(opt_fut?, …)` does let that `?` refer to the callsite scope. -mod test_join_function_like_value_arg_semantics { - use super::*; - - async fn async_fn(_: impl Sized) {} - - // no need to _run_ this test, just to compile it. - fn _join_does_not_unnecessarily_move_mentioned_bindings() { - let not_copy = vec![()]; - let _ = join!(async_fn(¬_copy)); // should not move `not_copy` - let _ = ¬_copy; // OK - } - - #[test] - fn join_lets_control_flow_effects_such_as_try_flow_through() { - let maybe_fut = None; - if false { - *&mut { maybe_fut } = Some(async {}); - loop {} - } - assert!(Option::is_none(&try { join!(maybe_fut?, async { unreachable!() }) })); - } - - #[test] - fn join_is_able_to_handle_temporaries() { - let _ = join!(async_fn(&String::from("temporary"))); - let () = block_on(join!(async_fn(&String::from("temporary")))); - } -} - -fn block_on(fut: impl Future) { - struct Waker; - impl Wake for Waker { - fn wake(self: Arc) { - thread::current().unpark() - } - } - - let waker = Arc::new(Waker).into(); - let mut cx = Context::from_waker(&waker); - let mut fut = Box::pin(fut); - - loop { - match fut.as_mut().poll(&mut cx) { - Poll::Ready(_) => break, - Poll::Pending => thread::park(), - } - } -} - -// just tests by whether or not this compiles -fn _pending_impl_all_auto_traits() { - use std::panic::{RefUnwindSafe, UnwindSafe}; - fn all_auto_traits() {} - - all_auto_traits::>(); -} diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs deleted file mode 100644 index 1f10a4733b0..00000000000 --- a/library/core/tests/hash/mod.rs +++ /dev/null @@ -1,167 +0,0 @@ -mod sip; - -use std::hash::{BuildHasher, Hash, Hasher}; -use std::ptr; -use std::rc::Rc; - -#[derive(Default)] -struct MyHasher { - hash: u64, -} - -impl Hasher for MyHasher { - fn write(&mut self, buf: &[u8]) { - for byte in buf { - self.hash += *byte as u64; - } - } - fn write_str(&mut self, s: &str) { - self.write(s.as_bytes()); - self.write_u8(0xFF); - } - fn finish(&self) -> u64 { - self.hash - } -} - -#[test] -fn test_writer_hasher() { - // FIXME(#110395) - /* const */ - fn hash(t: &T) -> u64 { - let mut s = MyHasher { hash: 0 }; - t.hash(&mut s); - s.finish() - } - - /* const { - // FIXME(fee1-dead): assert_eq - assert!(hash(&()) == 0); - assert!(hash(&5_u8) == 5); - assert!(hash(&5_u16) == 5); - assert!(hash(&5_u32) == 5); - - assert!(hash(&'a') == 97); - - let s: &str = "a"; - assert!(hash(&s) == 97 + 0xFF); - }; */ - - assert_eq!(hash(&()), 0); - - assert_eq!(hash(&5_u8), 5); - assert_eq!(hash(&5_u16), 5); - assert_eq!(hash(&5_u32), 5); - assert_eq!(hash(&5_u64), 5); - assert_eq!(hash(&5_usize), 5); - - assert_eq!(hash(&5_i8), 5); - assert_eq!(hash(&5_i16), 5); - assert_eq!(hash(&5_i32), 5); - assert_eq!(hash(&5_i64), 5); - assert_eq!(hash(&5_isize), 5); - - assert_eq!(hash(&false), 0); - assert_eq!(hash(&true), 1); - - assert_eq!(hash(&'a'), 97); - - let s: &str = "a"; - assert_eq!(hash(&s), 97 + 0xFF); - let s: Box = String::from("a").into_boxed_str(); - assert_eq!(hash(&s), 97 + 0xFF); - let s: Rc<&str> = Rc::new("a"); - assert_eq!(hash(&s), 97 + 0xFF); - let cs: &[u8] = &[1, 2, 3]; - assert_eq!(hash(&cs), 9); - let cs: Box<[u8]> = Box::new([1, 2, 3]); - assert_eq!(hash(&cs), 9); - let cs: Rc<[u8]> = Rc::new([1, 2, 3]); - assert_eq!(hash(&cs), 9); - - let ptr = ptr::without_provenance::(5_usize); - assert_eq!(hash(&ptr), 5); - - let ptr = ptr::without_provenance_mut::(5_usize); - assert_eq!(hash(&ptr), 5); - - if cfg!(miri) { - // Miri cannot hash pointers - return; - } - - let cs: &mut [u8] = &mut [1, 2, 3]; - let ptr = cs.as_ptr(); - let slice_ptr = cs as *const [u8]; - assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64); - - let slice_ptr = cs as *mut [u8]; - assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64); -} - -struct Custom { - hash: u64, -} - -#[derive(Default)] -struct CustomHasher { - output: u64, -} - -impl Hasher for CustomHasher { - fn finish(&self) -> u64 { - self.output - } - fn write(&mut self, _: &[u8]) { - panic!() - } - fn write_u64(&mut self, data: u64) { - self.output = data; - } -} - -impl Hash for Custom { - fn hash(&self, state: &mut H) { - state.write_u64(self.hash); - } -} - -#[test] -fn test_custom_state() { - // FIXME(#110395) - /* const */ - fn hash(t: &T) -> u64 { - let mut c = CustomHasher { output: 0 }; - t.hash(&mut c); - c.finish() - } - - assert_eq!(hash(&Custom { hash: 5 }), 5); - - // const { assert!(hash(&Custom { hash: 6 }) == 6) }; -} - -#[test] -fn test_indirect_hasher() { - let mut hasher = MyHasher { hash: 0 }; - { - let mut indirect_hasher: &mut dyn Hasher = &mut hasher; - 5u32.hash(&mut indirect_hasher); - } - assert_eq!(hasher.hash, 5); -} - -#[test] -fn test_build_hasher_dyn_compatible() { - use std::hash::{DefaultHasher, RandomState}; - - let _: &dyn BuildHasher = &RandomState::new(); -} - -// just tests by whether or not this compiles -fn _build_hasher_default_impl_all_auto_traits() { - use std::panic::{RefUnwindSafe, UnwindSafe}; - fn all_auto_traits() {} - - all_auto_traits::>(); -} diff --git a/library/core/tests/hash/sip.rs b/library/core/tests/hash/sip.rs deleted file mode 100644 index f79954f916b..00000000000 --- a/library/core/tests/hash/sip.rs +++ /dev/null @@ -1,323 +0,0 @@ -#![allow(deprecated)] - -use core::hash::{Hash, Hasher, SipHasher, SipHasher13}; -use core::{mem, slice}; - -// Hash just the bytes of the slice, without length prefix -struct Bytes<'a>(&'a [u8]); - -impl<'a> Hash for Bytes<'a> { - fn hash(&self, state: &mut H) { - let Bytes(v) = *self; - state.write(v); - } -} - -fn hash_with(mut st: H, x: &T) -> u64 { - x.hash(&mut st); - st.finish() -} - -fn hash(x: &T) -> u64 { - hash_with(SipHasher::new(), x) -} - -/* FIXME(#110395) -#[test] -const fn test_const_sip() { - let val1 = 0x45; - let val2 = 0xfeed; - - const fn const_hash(x: &T) -> u64 { - let mut st = SipHasher::new(); - x.hash(&mut st); - st.finish() - } - - assert!(const_hash(&(val1)) != const_hash(&(val2))); -} -*/ - -#[test] -#[allow(unused_must_use)] -fn test_siphash_1_3() { - let vecs: [[u8; 8]; 64] = [ - [0xdc, 0xc4, 0x0f, 0x05, 0x58, 0x01, 0xac, 0xab], - [0x93, 0xca, 0x57, 0x7d, 0xf3, 0x9b, 0xf4, 0xc9], - [0x4d, 0xd4, 0xc7, 0x4d, 0x02, 0x9b, 0xcb, 0x82], - [0xfb, 0xf7, 0xdd, 0xe7, 0xb8, 0x0a, 0xf8, 0x8b], - [0x28, 0x83, 0xd3, 0x88, 0x60, 0x57, 0x75, 0xcf], - [0x67, 0x3b, 0x53, 0x49, 0x2f, 0xd5, 0xf9, 0xde], - [0xa7, 0x22, 0x9f, 0xc5, 0x50, 0x2b, 0x0d, 0xc5], - [0x40, 0x11, 0xb1, 0x9b, 0x98, 0x7d, 0x92, 0xd3], - [0x8e, 0x9a, 0x29, 0x8d, 0x11, 0x95, 0x90, 0x36], - [0xe4, 0x3d, 0x06, 0x6c, 0xb3, 0x8e, 0xa4, 0x25], - [0x7f, 0x09, 0xff, 0x92, 0xee, 0x85, 0xde, 0x79], - [0x52, 0xc3, 0x4d, 0xf9, 0xc1, 0x18, 0xc1, 0x70], - [0xa2, 0xd9, 0xb4, 0x57, 0xb1, 0x84, 0xa3, 0x78], - [0xa7, 0xff, 0x29, 0x12, 0x0c, 0x76, 0x6f, 0x30], - [0x34, 0x5d, 0xf9, 0xc0, 0x11, 0xa1, 0x5a, 0x60], - [0x56, 0x99, 0x51, 0x2a, 0x6d, 0xd8, 0x20, 0xd3], - [0x66, 0x8b, 0x90, 0x7d, 0x1a, 0xdd, 0x4f, 0xcc], - [0x0c, 0xd8, 0xdb, 0x63, 0x90, 0x68, 0xf2, 0x9c], - [0x3e, 0xe6, 0x73, 0xb4, 0x9c, 0x38, 0xfc, 0x8f], - [0x1c, 0x7d, 0x29, 0x8d, 0xe5, 0x9d, 0x1f, 0xf2], - [0x40, 0xe0, 0xcc, 0xa6, 0x46, 0x2f, 0xdc, 0xc0], - [0x44, 0xf8, 0x45, 0x2b, 0xfe, 0xab, 0x92, 0xb9], - [0x2e, 0x87, 0x20, 0xa3, 0x9b, 0x7b, 0xfe, 0x7f], - [0x23, 0xc1, 0xe6, 0xda, 0x7f, 0x0e, 0x5a, 0x52], - [0x8c, 0x9c, 0x34, 0x67, 0xb2, 0xae, 0x64, 0xf4], - [0x79, 0x09, 0x5b, 0x70, 0x28, 0x59, 0xcd, 0x45], - [0xa5, 0x13, 0x99, 0xca, 0xe3, 0x35, 0x3e, 0x3a], - [0x35, 0x3b, 0xde, 0x4a, 0x4e, 0xc7, 0x1d, 0xa9], - [0x0d, 0xd0, 0x6c, 0xef, 0x02, 0xed, 0x0b, 0xfb], - [0xf4, 0xe1, 0xb1, 0x4a, 0xb4, 0x3c, 0xd9, 0x88], - [0x63, 0xe6, 0xc5, 0x43, 0xd6, 0x11, 0x0f, 0x54], - [0xbc, 0xd1, 0x21, 0x8c, 0x1f, 0xdd, 0x70, 0x23], - [0x0d, 0xb6, 0xa7, 0x16, 0x6c, 0x7b, 0x15, 0x81], - [0xbf, 0xf9, 0x8f, 0x7a, 0xe5, 0xb9, 0x54, 0x4d], - [0x3e, 0x75, 0x2a, 0x1f, 0x78, 0x12, 0x9f, 0x75], - [0x91, 0x6b, 0x18, 0xbf, 0xbe, 0xa3, 0xa1, 0xce], - [0x06, 0x62, 0xa2, 0xad, 0xd3, 0x08, 0xf5, 0x2c], - [0x57, 0x30, 0xc3, 0xa3, 0x2d, 0x1c, 0x10, 0xb6], - [0xa1, 0x36, 0x3a, 0xae, 0x96, 0x74, 0xf4, 0xb3], - [0x92, 0x83, 0x10, 0x7b, 0x54, 0x57, 0x6b, 0x62], - [0x31, 0x15, 0xe4, 0x99, 0x32, 0x36, 0xd2, 0xc1], - [0x44, 0xd9, 0x1a, 0x3f, 0x92, 0xc1, 0x7c, 0x66], - [0x25, 0x88, 0x13, 0xc8, 0xfe, 0x4f, 0x70, 0x65], - [0xa6, 0x49, 0x89, 0xc2, 0xd1, 0x80, 0xf2, 0x24], - [0x6b, 0x87, 0xf8, 0xfa, 0xed, 0x1c, 0xca, 0xc2], - [0x96, 0x21, 0x04, 0x9f, 0xfc, 0x4b, 0x16, 0xc2], - [0x23, 0xd6, 0xb1, 0x68, 0x93, 0x9c, 0x6e, 0xa1], - [0xfd, 0x14, 0x51, 0x8b, 0x9c, 0x16, 0xfb, 0x49], - [0x46, 0x4c, 0x07, 0xdf, 0xf8, 0x43, 0x31, 0x9f], - [0xb3, 0x86, 0xcc, 0x12, 0x24, 0xaf, 0xfd, 0xc6], - [0x8f, 0x09, 0x52, 0x0a, 0xd1, 0x49, 0xaf, 0x7e], - [0x9a, 0x2f, 0x29, 0x9d, 0x55, 0x13, 0xf3, 0x1c], - [0x12, 0x1f, 0xf4, 0xa2, 0xdd, 0x30, 0x4a, 0xc4], - [0xd0, 0x1e, 0xa7, 0x43, 0x89, 0xe9, 0xfa, 0x36], - [0xe6, 0xbc, 0xf0, 0x73, 0x4c, 0xb3, 0x8f, 0x31], - [0x80, 0xe9, 0xa7, 0x70, 0x36, 0xbf, 0x7a, 0xa2], - [0x75, 0x6d, 0x3c, 0x24, 0xdb, 0xc0, 0xbc, 0xb4], - [0x13, 0x15, 0xb7, 0xfd, 0x52, 0xd8, 0xf8, 0x23], - [0x08, 0x8a, 0x7d, 0xa6, 0x4d, 0x5f, 0x03, 0x8f], - [0x48, 0xf1, 0xe8, 0xb7, 0xe5, 0xd0, 0x9c, 0xd8], - [0xee, 0x44, 0xa6, 0xf7, 0xbc, 0xe6, 0xf4, 0xf6], - [0xf2, 0x37, 0x18, 0x0f, 0xd8, 0x9a, 0xc5, 0xae], - [0xe0, 0x94, 0x66, 0x4b, 0x15, 0xf6, 0xb2, 0xc3], - [0xa8, 0xb3, 0xbb, 0xb7, 0x62, 0x90, 0x19, 0x9d], - ]; - - let k0 = 0x_07_06_05_04_03_02_01_00; - let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; - let mut buf = Vec::new(); - let mut t = 0; - let mut state_inc = SipHasher13::new_with_keys(k0, k1); - - while t < 64 { - let vec = u64::from_le_bytes(vecs[t]); - let out = hash_with(SipHasher13::new_with_keys(k0, k1), &Bytes(&buf)); - assert_eq!(vec, out); - - let full = hash_with(SipHasher13::new_with_keys(k0, k1), &Bytes(&buf)); - let i = state_inc.finish(); - - assert_eq!(full, i); - assert_eq!(full, vec); - - buf.push(t as u8); - Hasher::write(&mut state_inc, &[t as u8]); - - t += 1; - } -} - -#[test] -#[allow(unused_must_use)] -fn test_siphash_2_4() { - let vecs: [[u8; 8]; 64] = [ - [0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72], - [0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74], - [0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d], - [0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85], - [0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf], - [0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18], - [0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb], - [0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab], - [0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93], - [0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e], - [0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a], - [0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4], - [0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75], - [0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14], - [0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7], - [0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1], - [0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f], - [0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69], - [0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b], - [0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb], - [0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe], - [0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0], - [0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93], - [0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8], - [0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8], - [0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc], - [0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17], - [0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f], - [0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde], - [0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6], - [0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad], - [0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32], - [0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71], - [0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7], - [0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12], - [0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15], - [0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31], - [0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02], - [0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca], - [0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a], - [0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e], - [0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad], - [0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18], - [0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4], - [0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9], - [0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9], - [0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb], - [0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0], - [0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6], - [0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7], - [0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee], - [0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1], - [0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a], - [0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81], - [0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f], - [0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24], - [0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7], - [0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea], - [0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60], - [0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66], - [0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c], - [0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f], - [0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5], - [0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95], - ]; - - let k0 = 0x_07_06_05_04_03_02_01_00; - let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; - let mut buf = Vec::new(); - let mut t = 0; - let mut state_inc = SipHasher::new_with_keys(k0, k1); - - while t < 64 { - let vec = u64::from_le_bytes(vecs[t]); - let out = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf)); - assert_eq!(vec, out); - - let full = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf)); - let i = state_inc.finish(); - - assert_eq!(full, i); - assert_eq!(full, vec); - - buf.push(t as u8); - Hasher::write(&mut state_inc, &[t as u8]); - - t += 1; - } -} - -#[test] -#[cfg(target_pointer_width = "32")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert_ne!(hash(&(val as u64)), hash(&(val as usize))); - assert_eq!(hash(&(val as u32)), hash(&(val as usize))); -} - -#[test] -#[cfg(target_pointer_width = "64")] -fn test_hash_usize() { - let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as usize))); - assert_ne!(hash(&(val as u32)), hash(&(val as usize))); -} - -#[test] -fn test_hash_idempotent() { - let val64 = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&val64), hash(&val64)); - let val32 = 0xdeadbeef_u32; - assert_eq!(hash(&val32), hash(&val32)); -} - -#[test] -fn test_hash_no_bytes_dropped_64() { - let val = 0xdeadbeef_deadbeef_u64; - - assert_ne!(hash(&val), hash(&zero_byte(val, 0))); - assert_ne!(hash(&val), hash(&zero_byte(val, 1))); - assert_ne!(hash(&val), hash(&zero_byte(val, 2))); - assert_ne!(hash(&val), hash(&zero_byte(val, 3))); - assert_ne!(hash(&val), hash(&zero_byte(val, 4))); - assert_ne!(hash(&val), hash(&zero_byte(val, 5))); - assert_ne!(hash(&val), hash(&zero_byte(val, 6))); - assert_ne!(hash(&val), hash(&zero_byte(val, 7))); - - fn zero_byte(val: u64, byte: usize) -> u64 { - assert!(byte < 8); - val & !(0xff << (byte * 8)) - } -} - -#[test] -fn test_hash_no_bytes_dropped_32() { - let val = 0xdeadbeef_u32; - - assert_ne!(hash(&val), hash(&zero_byte(val, 0))); - assert_ne!(hash(&val), hash(&zero_byte(val, 1))); - assert_ne!(hash(&val), hash(&zero_byte(val, 2))); - assert_ne!(hash(&val), hash(&zero_byte(val, 3))); - - fn zero_byte(val: u32, byte: usize) -> u32 { - assert!(byte < 4); - val & !(0xff << (byte * 8)) - } -} - -#[test] -fn test_hash_no_concat_alias() { - let s = ("aa", "bb"); - let t = ("aabb", ""); - let u = ("a", "abb"); - - assert_ne!(s, t); - assert_ne!(t, u); - assert_ne!(hash(&s), hash(&t)); - assert_ne!(hash(&s), hash(&u)); - - let u = [1, 0, 0, 0]; - let v = (&u[..1], &u[1..3], &u[3..]); - let w = (&u[..], &u[4..4], &u[4..4]); - - assert_ne!(v, w); - assert_ne!(hash(&v), hash(&w)); -} - -#[test] -fn test_write_short_works() { - let test_usize = 0xd0c0b0a0usize; - let mut h1 = SipHasher::new(); - h1.write_usize(test_usize); - h1.write(b"bytes"); - h1.write(b"string"); - h1.write_u8(0xFFu8); - h1.write_u8(0x01u8); - let mut h2 = SipHasher::new(); - h2.write(unsafe { - slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::()) - }); - h2.write(b"bytes"); - h2.write(b"string"); - h2.write(&[0xFFu8, 0x01u8]); - assert_eq!(h1.finish(), h2.finish()); -} diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs deleted file mode 100644 index 744a6a0d2dd..00000000000 --- a/library/core/tests/intrinsics.rs +++ /dev/null @@ -1,195 +0,0 @@ -use core::any::TypeId; -use core::intrinsics::assume; - -#[test] -fn test_typeid_sized_types() { - struct X; - struct Y(#[allow(dead_code)] u32); - - assert_eq!(TypeId::of::(), TypeId::of::()); - assert_eq!(TypeId::of::(), TypeId::of::()); - assert!(TypeId::of::() != TypeId::of::()); -} - -#[test] -fn test_typeid_unsized_types() { - trait Z {} - struct X(#[allow(dead_code)] str); - struct Y(#[allow(dead_code)] dyn Z + 'static); - - assert_eq!(TypeId::of::(), TypeId::of::()); - assert_eq!(TypeId::of::(), TypeId::of::()); - assert!(TypeId::of::() != TypeId::of::()); -} - -// Check that `const_assume` feature allow `assume` intrinsic -// to be used in const contexts. -#[test] -fn test_assume_can_be_in_const_contexts() { - const unsafe fn foo(x: usize, y: usize) -> usize { - // SAFETY: the entire function is not safe, - // but it is just an example not used elsewhere. - unsafe { assume(y != 0) }; - x / y - } - let rs = unsafe { foo(42, 97) }; - assert_eq!(rs, 0); -} - -#[test] -const fn test_write_bytes_in_const_contexts() { - use core::intrinsics::write_bytes; - - const TEST: [u32; 3] = { - let mut arr = [1u32, 2, 3]; - unsafe { - write_bytes(arr.as_mut_ptr(), 0, 2); - } - arr - }; - - assert!(TEST[0] == 0); - assert!(TEST[1] == 0); - assert!(TEST[2] == 3); - - const TEST2: [u32; 3] = { - let mut arr = [1u32, 2, 3]; - unsafe { - write_bytes(arr.as_mut_ptr(), 1, 2); - } - arr - }; - - assert!(TEST2[0] == 16843009); - assert!(TEST2[1] == 16843009); - assert!(TEST2[2] == 3); -} - -#[test] -fn test_hints_in_const_contexts() { - use core::intrinsics::{likely, unlikely}; - - // In const contexts, they just return their argument. - const { - assert!(true == likely(true)); - assert!(false == likely(false)); - assert!(true == unlikely(true)); - assert!(false == unlikely(false)); - assert!(42u32 == core::intrinsics::black_box(42u32)); - assert!(42u32 == core::hint::black_box(42u32)); - } -} - -#[test] -fn test_const_allocate_at_runtime() { - use core::intrinsics::const_allocate; - unsafe { - assert!(const_allocate(4, 4).is_null()); - } -} - -#[test] -fn test_const_deallocate_at_runtime() { - use core::intrinsics::const_deallocate; - const X: &u32 = &42u32; - let x = &0u32; - unsafe { - const_deallocate(X as *const _ as *mut u8, 4, 4); // nop - const_deallocate(x as *const _ as *mut u8, 4, 4); // nop - const_deallocate(core::ptr::null_mut(), 1, 1); // nop - } -} - -#[test] -fn test_three_way_compare_in_const_contexts() { - use core::cmp::Ordering::{self, *}; - use core::intrinsics::three_way_compare; - - const UNSIGNED_LESS: Ordering = three_way_compare(123_u16, 456); - const UNSIGNED_EQUAL: Ordering = three_way_compare(456_u16, 456); - const UNSIGNED_GREATER: Ordering = three_way_compare(789_u16, 456); - const CHAR_LESS: Ordering = three_way_compare('A', 'B'); - const CHAR_EQUAL: Ordering = three_way_compare('B', 'B'); - const CHAR_GREATER: Ordering = three_way_compare('C', 'B'); - const SIGNED_LESS: Ordering = three_way_compare(123_i64, 456); - const SIGNED_EQUAL: Ordering = three_way_compare(456_i64, 456); - const SIGNED_GREATER: Ordering = three_way_compare(789_i64, 456); - - assert_eq!(UNSIGNED_LESS, Less); - assert_eq!(UNSIGNED_EQUAL, Equal); - assert_eq!(UNSIGNED_GREATER, Greater); - assert_eq!(CHAR_LESS, Less); - assert_eq!(CHAR_EQUAL, Equal); - assert_eq!(CHAR_GREATER, Greater); - assert_eq!(SIGNED_LESS, Less); - assert_eq!(SIGNED_EQUAL, Equal); - assert_eq!(SIGNED_GREATER, Greater); -} - -fn fallback_cma( - a: T, - b: T, - c: T, - d: T, -) -> (T::Unsigned, T) { - a.carrying_mul_add(b, c, d) -} - -#[test] -fn carrying_mul_add_fallback_u32() { - let r = fallback_cma::(0x9e37_79b9, 0x7f4a_7c15, 0xf39c_c060, 0x5ced_c834); - assert_eq!(r, (0x2087_20c1, 0x4eab_8e1d)); - let r = fallback_cma::(0x1082_276b, 0xf3a2_7251, 0xf86c_6a11, 0xd0c1_8e95); - assert_eq!(r, (0x7aa0_1781, 0x0fb6_0528)); -} - -#[test] -fn carrying_mul_add_fallback_i32() { - let r = fallback_cma::(-1, -1, -1, -1); - assert_eq!(r, (u32::MAX, -1)); - let r = fallback_cma::(1, -1, 1, 1); - assert_eq!(r, (1, 0)); -} - -#[test] -fn carrying_mul_add_fallback_u128() { - assert_eq!(fallback_cma::(u128::MAX, u128::MAX, 0, 0), (1, u128::MAX - 1)); - assert_eq!(fallback_cma::(1, 1, 1, 1), (3, 0)); - assert_eq!(fallback_cma::(0, 0, u128::MAX, u128::MAX), (u128::MAX - 1, 1)); - assert_eq!( - fallback_cma::(u128::MAX, u128::MAX, u128::MAX, u128::MAX), - (u128::MAX, u128::MAX), - ); - - let r = fallback_cma::( - 0x243f6a8885a308d313198a2e03707344, - 0xa4093822299f31d0082efa98ec4e6c89, - 0x452821e638d01377be5466cf34e90c6c, - 0xc0ac29b7c97c50dd3f84d5b5b5470917, - ); - assert_eq!(r, (0x8050ec20ed554e40338d277e00b674e7, 0x1739ee6cea07da409182d003859b59d8)); - let r = fallback_cma::( - 0x9216d5d98979fb1bd1310ba698dfb5ac, - 0x2ffd72dbd01adfb7b8e1afed6a267e96, - 0xba7c9045f12c7f9924a19947b3916cf7, - 0x0801f2e2858efc16636920d871574e69, - ); - assert_eq!(r, (0x185525545fdb2fefb502a3a602efd628, 0x1b62d35fe3bff6b566f99667ef7ebfd6)); -} - -#[test] -fn carrying_mul_add_fallback_i128() { - assert_eq!(fallback_cma::(-1, -1, 0, 0), (1, 0)); - let r = fallback_cma::(-1, -1, -1, -1); - assert_eq!(r, (u128::MAX, -1)); - let r = fallback_cma::(1, -1, 1, 1); - assert_eq!(r, (1, 0)); - assert_eq!( - fallback_cma::(i128::MAX, i128::MAX, i128::MAX, i128::MAX), - (u128::MAX, i128::MAX / 2), - ); - assert_eq!( - fallback_cma::(i128::MIN, i128::MIN, i128::MAX, i128::MAX), - (u128::MAX - 1, -(i128::MIN / 2)), - ); -} diff --git a/library/core/tests/io/borrowed_buf.rs b/library/core/tests/io/borrowed_buf.rs deleted file mode 100644 index a5dd4e52577..00000000000 --- a/library/core/tests/io/borrowed_buf.rs +++ /dev/null @@ -1,167 +0,0 @@ -use core::io::BorrowedBuf; -use core::mem::MaybeUninit; - -/// Test that BorrowedBuf has the correct numbers when created with new -#[test] -fn new() { - let buf: &mut [_] = &mut [0; 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - assert_eq!(rbuf.filled().len(), 0); - assert_eq!(rbuf.init_len(), 16); - assert_eq!(rbuf.capacity(), 16); - assert_eq!(rbuf.unfilled().capacity(), 16); -} - -/// Test that BorrowedBuf has the correct numbers when created with uninit -#[test] -fn uninit() { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - assert_eq!(rbuf.filled().len(), 0); - assert_eq!(rbuf.init_len(), 0); - assert_eq!(rbuf.capacity(), 16); - assert_eq!(rbuf.unfilled().capacity(), 16); -} - -#[test] -fn initialize_unfilled() { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - rbuf.unfilled().ensure_init(); - - assert_eq!(rbuf.init_len(), 16); -} - -#[test] -fn advance_filled() { - let buf: &mut [_] = &mut [0; 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - rbuf.unfilled().advance(1); - - assert_eq!(rbuf.filled().len(), 1); - assert_eq!(rbuf.unfilled().capacity(), 15); -} - -#[test] -fn clear() { - let buf: &mut [_] = &mut [255; 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - rbuf.unfilled().advance(16); - - assert_eq!(rbuf.filled().len(), 16); - assert_eq!(rbuf.unfilled().capacity(), 0); - - rbuf.clear(); - - assert_eq!(rbuf.filled().len(), 0); - assert_eq!(rbuf.unfilled().capacity(), 16); - - assert_eq!(rbuf.unfilled().init_ref(), [255; 16]); -} - -#[test] -fn set_init() { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - unsafe { - rbuf.set_init(8); - } - - assert_eq!(rbuf.init_len(), 8); - - rbuf.unfilled().advance(4); - - unsafe { - rbuf.set_init(2); - } - - assert_eq!(rbuf.init_len(), 8); - - unsafe { - rbuf.set_init(8); - } - - assert_eq!(rbuf.init_len(), 8); -} - -#[test] -fn append() { - let buf: &mut [_] = &mut [MaybeUninit::new(255); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - rbuf.unfilled().append(&[0; 8]); - - assert_eq!(rbuf.init_len(), 8); - assert_eq!(rbuf.filled().len(), 8); - assert_eq!(rbuf.filled(), [0; 8]); - - rbuf.clear(); - - rbuf.unfilled().append(&[1; 16]); - - assert_eq!(rbuf.init_len(), 16); - assert_eq!(rbuf.filled().len(), 16); - assert_eq!(rbuf.filled(), [1; 16]); -} - -#[test] -fn reborrow_written() { - let buf: &mut [_] = &mut [MaybeUninit::new(0); 32]; - let mut buf: BorrowedBuf<'_> = buf.into(); - - let mut cursor = buf.unfilled(); - cursor.append(&[1; 16]); - - let mut cursor2 = cursor.reborrow(); - cursor2.append(&[2; 16]); - - assert_eq!(cursor2.written(), 32); - assert_eq!(cursor.written(), 32); - - assert_eq!(buf.unfilled().written(), 0); - assert_eq!(buf.init_len(), 32); - assert_eq!(buf.filled().len(), 32); - let filled = buf.filled(); - assert_eq!(&filled[..16], [1; 16]); - assert_eq!(&filled[16..], [2; 16]); -} - -#[test] -fn cursor_set_init() { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; - let mut rbuf: BorrowedBuf<'_> = buf.into(); - - unsafe { - rbuf.unfilled().set_init(8); - } - - assert_eq!(rbuf.init_len(), 8); - assert_eq!(rbuf.unfilled().init_ref().len(), 8); - assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(rbuf.unfilled().uninit_mut().len(), 8); - assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 16); - - rbuf.unfilled().advance(4); - - unsafe { - rbuf.unfilled().set_init(2); - } - - assert_eq!(rbuf.init_len(), 8); - - unsafe { - rbuf.unfilled().set_init(8); - } - - assert_eq!(rbuf.init_len(), 12); - assert_eq!(rbuf.unfilled().init_ref().len(), 8); - assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(rbuf.unfilled().uninit_mut().len(), 4); - assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 12); -} diff --git a/library/core/tests/io/mod.rs b/library/core/tests/io/mod.rs deleted file mode 100644 index a24893a525a..00000000000 --- a/library/core/tests/io/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod borrowed_buf; diff --git a/library/core/tests/iter/adapters/array_chunks.rs b/library/core/tests/iter/adapters/array_chunks.rs deleted file mode 100644 index fb19a519f63..00000000000 --- a/library/core/tests/iter/adapters/array_chunks.rs +++ /dev/null @@ -1,179 +0,0 @@ -use core::iter::{self}; - -use super::*; - -#[test] -fn test_iterator_array_chunks_infer() { - let xs = [1, 1, 2, -2, 6, 0, 3, 1]; - for [a, b, c] in xs.iter().copied().array_chunks() { - assert_eq!(a + b + c, 4); - } -} - -#[test] -fn test_iterator_array_chunks_clone_and_drop() { - let count = Cell::new(0); - let mut it = (0..5).map(|_| CountDrop::new(&count)).array_chunks::<3>(); - assert_eq!(it.by_ref().count(), 1); - assert_eq!(count.get(), 3); - let mut it2 = it.clone(); - assert_eq!(count.get(), 3); - assert_eq!(it.into_remainder().unwrap().len(), 2); - assert_eq!(count.get(), 5); - assert!(it2.next().is_none()); - assert_eq!(it2.into_remainder().unwrap().len(), 2); - assert_eq!(count.get(), 7); -} - -#[test] -fn test_iterator_array_chunks_remainder() { - let mut it = (0..11).array_chunks::<4>(); - assert_eq!(it.next(), Some([0, 1, 2, 3])); - assert_eq!(it.next(), Some([4, 5, 6, 7])); - assert_eq!(it.next(), None); - assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]); -} - -#[test] -fn test_iterator_array_chunks_size_hint() { - let it = (0..6).array_chunks::<1>(); - assert_eq!(it.size_hint(), (6, Some(6))); - - let it = (0..6).array_chunks::<3>(); - assert_eq!(it.size_hint(), (2, Some(2))); - - let it = (0..6).array_chunks::<5>(); - assert_eq!(it.size_hint(), (1, Some(1))); - - let it = (0..6).array_chunks::<7>(); - assert_eq!(it.size_hint(), (0, Some(0))); - - let it = (1..).array_chunks::<2>(); - assert_eq!(it.size_hint(), (usize::MAX / 2, None)); - - let it = (1..).filter(|x| x % 2 != 0).array_chunks::<2>(); - assert_eq!(it.size_hint(), (0, None)); -} - -#[test] -fn test_iterator_array_chunks_count() { - let it = (0..6).array_chunks::<1>(); - assert_eq!(it.count(), 6); - - let it = (0..6).array_chunks::<3>(); - assert_eq!(it.count(), 2); - - let it = (0..6).array_chunks::<5>(); - assert_eq!(it.count(), 1); - - let it = (0..6).array_chunks::<7>(); - assert_eq!(it.count(), 0); - - let it = (0..6).filter(|x| x % 2 == 0).array_chunks::<2>(); - assert_eq!(it.count(), 1); - - let it = iter::empty::().array_chunks::<2>(); - assert_eq!(it.count(), 0); - - let it = [(); usize::MAX].iter().array_chunks::<2>(); - assert_eq!(it.count(), usize::MAX / 2); -} - -#[test] -fn test_iterator_array_chunks_next_and_next_back() { - let mut it = (0..11).array_chunks::<3>(); - assert_eq!(it.next(), Some([0, 1, 2])); - assert_eq!(it.next_back(), Some([6, 7, 8])); - assert_eq!(it.next(), Some([3, 4, 5])); - assert_eq!(it.next_back(), None); - assert_eq!(it.next(), None); - assert_eq!(it.next_back(), None); - assert_eq!(it.next(), None); - assert_eq!(it.into_remainder().unwrap().as_slice(), &[9, 10]); -} - -#[test] -fn test_iterator_array_chunks_rev_remainder() { - let mut it = (0..11).array_chunks::<4>(); - { - let mut it = it.by_ref().rev(); - assert_eq!(it.next(), Some([4, 5, 6, 7])); - assert_eq!(it.next(), Some([0, 1, 2, 3])); - assert_eq!(it.next(), None); - assert_eq!(it.next(), None); - } - assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]); -} - -#[test] -fn test_iterator_array_chunks_try_fold() { - let count = Cell::new(0); - let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); - let result: Result<_, ()> = it.by_ref().try_fold(0, |acc, _item| Ok(acc + 1)); - assert_eq!(result, Ok(3)); - assert_eq!(count.get(), 9); - drop(it); - assert_eq!(count.get(), 10); - - let count = Cell::new(0); - let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); - let result = it.by_ref().try_fold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) }); - assert_eq!(result, Err(2)); - assert_eq!(count.get(), 9); - drop(it); - assert_eq!(count.get(), 9); -} - -#[test] -fn test_iterator_array_chunks_fold() { - let result = (1..11).array_chunks::<3>().fold(0, |acc, [a, b, c]| { - assert_eq!(acc + 1, a); - assert_eq!(acc + 2, b); - assert_eq!(acc + 3, c); - acc + 3 - }); - assert_eq!(result, 9); - - let count = Cell::new(0); - let result = - (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().fold(0, |acc, _item| acc + 1); - assert_eq!(result, 3); - // fold impls may or may not process the remainder - assert!(count.get() <= 10 && count.get() >= 9); -} - -#[test] -fn test_iterator_array_chunks_try_rfold() { - let count = Cell::new(0); - let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); - let result: Result<_, ()> = it.try_rfold(0, |acc, _item| Ok(acc + 1)); - assert_eq!(result, Ok(3)); - assert_eq!(count.get(), 9); - drop(it); - assert_eq!(count.get(), 10); - - let count = Cell::new(0); - let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); - let result = it.try_rfold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) }); - assert_eq!(result, Err(2)); - assert_eq!(count.get(), 9); - drop(it); - assert_eq!(count.get(), 10); -} - -#[test] -fn test_iterator_array_chunks_rfold() { - let result = (1..11).array_chunks::<3>().rfold(0, |acc, [a, b, c]| { - assert_eq!(10 - (acc + 1), c); - assert_eq!(10 - (acc + 2), b); - assert_eq!(10 - (acc + 3), a); - acc + 3 - }); - assert_eq!(result, 9); - - let count = Cell::new(0); - let result = - (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().rfold(0, |acc, _item| acc + 1); - assert_eq!(result, 3); - assert_eq!(count.get(), 10); -} diff --git a/library/core/tests/iter/adapters/by_ref_sized.rs b/library/core/tests/iter/adapters/by_ref_sized.rs deleted file mode 100644 index a9c066f0e8c..00000000000 --- a/library/core/tests/iter/adapters/by_ref_sized.rs +++ /dev/null @@ -1,20 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_by_ref_sized() { - let a = ['a', 'b', 'c', 'd']; - - let mut s = String::from("Z"); - let mut it = a.iter().copied(); - ByRefSized(&mut it).take(2).for_each(|x| s.push(x)); - assert_eq!(s, "Zab"); - ByRefSized(&mut it).fold((), |(), x| s.push(x)); - assert_eq!(s, "Zabcd"); - - let mut s = String::from("Z"); - let mut it = a.iter().copied(); - ByRefSized(&mut it).rev().take(2).for_each(|x| s.push(x)); - assert_eq!(s, "Zdc"); - ByRefSized(&mut it).rfold((), |(), x| s.push(x)); - assert_eq!(s, "Zdcba"); -} diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs deleted file mode 100644 index 1b2c026ee1e..00000000000 --- a/library/core/tests/iter/adapters/chain.rs +++ /dev/null @@ -1,293 +0,0 @@ -use core::iter::*; -use core::num::NonZero; - -use super::*; - -#[test] -fn test_chain() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; - assert_eq!(Vec::from_iter(chain(xs, ys)), expected); -} - -#[test] -fn test_iterator_chain() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; - let it = xs.iter().chain(&ys); - let mut i = 0; - for &x in it { - assert_eq!(x, expected[i]); - i += 1; - } - assert_eq!(i, expected.len()); - - let ys = (30..).step_by(10).take(4); - let it = xs.iter().cloned().chain(ys); - let mut i = 0; - for x in it { - assert_eq!(x, expected[i]); - i += 1; - } - assert_eq!(i, expected.len()); -} - -#[test] -fn test_iterator_chain_advance_by() { - fn test_chain(xs: &[i32], ys: &[i32]) { - let len = xs.len() + ys.len(); - - for i in 0..xs.len() { - let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - assert_eq!(iter.advance_by(i), Ok(())); - assert_eq!(iter.next(), Some(&xs[i])); - assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (len - i - 1)).unwrap())); - assert_eq!(iter.advance_by(0), Ok(())); - } - - for i in 0..ys.len() { - let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - assert_eq!(iter.advance_by(xs.len() + i), Ok(())); - assert_eq!(iter.next(), Some(&ys[i])); - assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (ys.len() - i - 1)).unwrap())); - assert_eq!(iter.advance_by(0), Ok(())); - } - - let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_by(len), Ok(())); - assert_eq!(iter.next(), None); - assert_eq!(iter.advance_by(0), Ok(())); - - let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_by(len + 1), Err(NonZero::new(1).unwrap())); - assert_eq!(iter.advance_by(0), Ok(())); - } - - test_chain(&[], &[]); - test_chain(&[], &[0, 1, 2, 3, 4, 5]); - test_chain(&[0, 1, 2, 3, 4, 5], &[]); - test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); -} - -#[test] -fn test_iterator_chain_advance_back_by() { - fn test_chain(xs: &[i32], ys: &[i32]) { - let len = xs.len() + ys.len(); - - for i in 0..ys.len() { - let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - assert_eq!(iter.advance_back_by(i), Ok(())); - assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1])); - assert_eq!(iter.advance_back_by(100), Err(NonZero::new(100 - (len - i - 1)).unwrap())); - assert_eq!(iter.advance_back_by(0), Ok(())); - } - - for i in 0..xs.len() { - let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - assert_eq!(iter.advance_back_by(ys.len() + i), Ok(())); - assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1])); - assert_eq!( - iter.advance_back_by(100), - Err(NonZero::new(100 - (xs.len() - i - 1)).unwrap()) - ); - assert_eq!(iter.advance_back_by(0), Ok(())); - } - - let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_back_by(len), Ok(())); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.advance_back_by(0), Ok(())); - - let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_back_by(len + 1), Err(NonZero::new(1).unwrap())); - assert_eq!(iter.advance_back_by(0), Ok(())); - } - - test_chain(&[], &[]); - test_chain(&[], &[0, 1, 2, 3, 4, 5]); - test_chain(&[0, 1, 2, 3, 4, 5], &[]); - test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); -} - -#[test] -fn test_iterator_chain_nth() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let zs = []; - let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; - for (i, x) in expected.iter().enumerate() { - assert_eq!(Some(x), xs.iter().chain(&ys).nth(i)); - } - assert_eq!(zs.iter().chain(&xs).nth(0), Some(&0)); - - let mut it = xs.iter().chain(&zs); - assert_eq!(it.nth(5), Some(&5)); - assert_eq!(it.next(), None); -} - -#[test] -fn test_iterator_chain_nth_back() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let zs = []; - let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; - for (i, x) in expected.iter().rev().enumerate() { - assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i)); - } - assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5)); - - let mut it = xs.iter().chain(&zs); - assert_eq!(it.nth_back(5), Some(&0)); - assert_eq!(it.next(), None); -} - -#[test] -fn test_iterator_chain_last() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let zs = []; - assert_eq!(xs.iter().chain(&ys).last(), Some(&60)); - assert_eq!(zs.iter().chain(&ys).last(), Some(&60)); - assert_eq!(ys.iter().chain(&zs).last(), Some(&60)); - assert_eq!(zs.iter().chain(&zs).last(), None); -} - -#[test] -fn test_iterator_chain_count() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let zs = []; - assert_eq!(xs.iter().chain(&ys).count(), 10); - assert_eq!(zs.iter().chain(&ys).count(), 4); -} - -#[test] -fn test_iterator_chain_find() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; - let mut iter = xs.iter().chain(&ys); - assert_eq!(iter.find(|&&i| i == 4), Some(&4)); - assert_eq!(iter.next(), Some(&5)); - assert_eq!(iter.find(|&&i| i == 40), Some(&40)); - assert_eq!(iter.next(), Some(&50)); - assert_eq!(iter.find(|&&i| i == 100), None); - assert_eq!(iter.next(), None); -} - -#[test] -fn test_iterator_chain_size_hint() { - // this chains an iterator of length 0 with an iterator of length 1, - // so after calling `.next()` once, the iterator is empty and the - // state is `ChainState::Back`. `.size_hint()` should now disregard - // the size hint of the left iterator - let mut iter = Toggle { is_empty: true }.chain(once(())); - assert_eq!(iter.next(), Some(())); - assert_eq!(iter.size_hint(), (0, Some(0))); - - let mut iter = once(()).chain(Toggle { is_empty: true }); - assert_eq!(iter.next_back(), Some(())); - assert_eq!(iter.size_hint(), (0, Some(0))); -} - -#[test] -fn test_iterator_chain_unfused() { - // Chain shouldn't be fused in its second iterator, depending on direction - let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true }); - assert!(iter.next().is_none()); - assert!(iter.next().is_some()); - assert!(iter.next().is_none()); - - let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty())); - assert!(iter.next_back().is_none()); - assert!(iter.next_back().is_some()); - assert!(iter.next_back().is_none()); -} - -#[test] -fn test_chain_fold() { - let xs = [1, 2, 3]; - let ys = [1, 2, 0]; - - let mut iter = xs.iter().chain(&ys); - iter.next(); - let mut result = Vec::new(); - iter.fold((), |(), &elt| result.push(elt)); - assert_eq!(&[2, 3, 1, 2, 0], &result[..]); -} - -#[test] -fn test_chain_try_folds() { - let c = || (0..10).chain(10..20); - - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!(c().try_fold(7, f), (0..20).try_fold(7, f)); - assert_eq!(c().try_rfold(7, f), (0..20).rev().try_fold(7, f)); - - let mut iter = c(); - assert_eq!(iter.position(|x| x == 5), Some(5)); - assert_eq!(iter.next(), Some(6), "stopped in front, state Both"); - assert_eq!(iter.position(|x| x == 13), Some(6)); - assert_eq!(iter.next(), Some(14), "stopped in back, state Back"); - assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((15..20).sum())); - - let mut iter = c().rev(); // use rev to access try_rfold - assert_eq!(iter.position(|x| x == 15), Some(4)); - assert_eq!(iter.next(), Some(14), "stopped in back, state Both"); - assert_eq!(iter.position(|x| x == 5), Some(8)); - assert_eq!(iter.next(), Some(4), "stopped in front, state Front"); - assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((0..4).sum())); - - let mut iter = c(); - iter.by_ref().rev().nth(14); // skip the last 15, ending in state Front - assert_eq!(iter.try_fold(7, f), (0..5).try_fold(7, f)); - - let mut iter = c(); - iter.nth(14); // skip the first 15, ending in state Back - assert_eq!(iter.try_rfold(7, f), (15..20).try_rfold(7, f)); -} - -#[test] -fn test_double_ended_chain() { - let xs = [1, 2, 3, 4, 5]; - let ys = [7, 9, 11]; - let mut it = xs.iter().chain(&ys).rev(); - assert_eq!(it.next().unwrap(), &11); - assert_eq!(it.next().unwrap(), &9); - assert_eq!(it.next_back().unwrap(), &1); - assert_eq!(it.next_back().unwrap(), &2); - assert_eq!(it.next_back().unwrap(), &3); - assert_eq!(it.next_back().unwrap(), &4); - assert_eq!(it.next_back().unwrap(), &5); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back(), None); - - // test that .chain() is well behaved with an unfused iterator - struct CrazyIterator(bool); - impl CrazyIterator { - fn new() -> CrazyIterator { - CrazyIterator(false) - } - } - impl Iterator for CrazyIterator { - type Item = i32; - fn next(&mut self) -> Option { - if self.0 { - Some(99) - } else { - self.0 = true; - None - } - } - } - - impl DoubleEndedIterator for CrazyIterator { - fn next_back(&mut self) -> Option { - self.next() - } - } - - assert_eq!(CrazyIterator::new().chain(0..10).rev().last(), Some(0)); - assert!((0..10).chain(CrazyIterator::new()).rev().any(|i| i == 0)); -} diff --git a/library/core/tests/iter/adapters/cloned.rs b/library/core/tests/iter/adapters/cloned.rs deleted file mode 100644 index 78babb7feab..00000000000 --- a/library/core/tests/iter/adapters/cloned.rs +++ /dev/null @@ -1,52 +0,0 @@ -use core::iter::*; - -#[test] -fn test_cloned() { - let xs = [2, 4, 6, 8]; - - let mut it = xs.iter().cloned(); - assert_eq!(it.len(), 4); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.len(), 3); - assert_eq!(it.next(), Some(4)); - assert_eq!(it.len(), 2); - assert_eq!(it.next_back(), Some(8)); - assert_eq!(it.len(), 1); - assert_eq!(it.next_back(), Some(6)); - assert_eq!(it.len(), 0); - assert_eq!(it.next_back(), None); -} - -#[test] -fn test_cloned_side_effects() { - let mut count = 0; - { - let iter = [1, 2, 3] - .iter() - .map(|x| { - count += 1; - x - }) - .cloned() - .zip(&[1]); - for _ in iter {} - } - assert_eq!(count, 2); -} - -#[test] -fn test_cloned_try_folds() { - let a = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let f = &|acc, x| i32::checked_add(2 * acc, x); - let f_ref = &|acc, &x| i32::checked_add(2 * acc, x); - assert_eq!(a.iter().cloned().try_fold(7, f), a.iter().try_fold(7, f_ref)); - assert_eq!(a.iter().cloned().try_rfold(7, f), a.iter().try_rfold(7, f_ref)); - - let a = [10, 20, 30, 40, 100, 60, 70, 80, 90]; - let mut iter = a.iter().cloned(); - assert_eq!(iter.try_fold(0_i8, |acc, x| acc.checked_add(x)), None); - assert_eq!(iter.next(), Some(60)); - let mut iter = a.iter().cloned(); - assert_eq!(iter.try_rfold(0_i8, |acc, x| acc.checked_add(x)), None); - assert_eq!(iter.next_back(), Some(70)); -} diff --git a/library/core/tests/iter/adapters/copied.rs b/library/core/tests/iter/adapters/copied.rs deleted file mode 100644 index b12f2035dc1..00000000000 --- a/library/core/tests/iter/adapters/copied.rs +++ /dev/null @@ -1,18 +0,0 @@ -use core::iter::*; - -#[test] -fn test_copied() { - let xs = [2, 4, 6, 8]; - - let mut it = xs.iter().copied(); - assert_eq!(it.len(), 4); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.len(), 3); - assert_eq!(it.next(), Some(4)); - assert_eq!(it.len(), 2); - assert_eq!(it.next_back(), Some(8)); - assert_eq!(it.len(), 1); - assert_eq!(it.next_back(), Some(6)); - assert_eq!(it.len(), 0); - assert_eq!(it.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/cycle.rs b/library/core/tests/iter/adapters/cycle.rs deleted file mode 100644 index 8831c09b48b..00000000000 --- a/library/core/tests/iter/adapters/cycle.rs +++ /dev/null @@ -1,31 +0,0 @@ -use core::iter::*; - -#[test] -fn test_cycle() { - let cycle_len = 3; - let it = (0..).step_by(1).take(cycle_len).cycle(); - assert_eq!(it.size_hint(), (usize::MAX, None)); - for (i, x) in it.take(100).enumerate() { - assert_eq!(i % cycle_len, x); - } - - let mut it = (0..).step_by(1).take(0).cycle(); - assert_eq!(it.size_hint(), (0, Some(0))); - assert_eq!(it.next(), None); - - assert_eq!(empty::().cycle().fold(0, |acc, x| acc + x), 0); - - assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4); - - assert_eq!((0..10).cycle().take(5).sum::(), 10); - assert_eq!((0..10).cycle().take(15).sum::(), 55); - assert_eq!((0..10).cycle().take(25).sum::(), 100); - - let mut iter = (0..10).cycle(); - iter.nth(14); - assert_eq!(iter.take(8).sum::(), 38); - - let mut iter = (0..10).cycle(); - iter.nth(9); - assert_eq!(iter.take(3).sum::(), 3); -} diff --git a/library/core/tests/iter/adapters/enumerate.rs b/library/core/tests/iter/adapters/enumerate.rs deleted file mode 100644 index b57d51c077e..00000000000 --- a/library/core/tests/iter/adapters/enumerate.rs +++ /dev/null @@ -1,122 +0,0 @@ -use core::iter::*; -use core::num::NonZero; - -#[test] -fn test_iterator_enumerate() { - let xs = [0, 1, 2, 3, 4, 5]; - let it = xs.iter().enumerate(); - for (i, &x) in it { - assert_eq!(i, x); - } -} - -#[test] -fn test_iterator_enumerate_nth() { - let xs = [0, 1, 2, 3, 4, 5]; - for (i, &x) in xs.iter().enumerate() { - assert_eq!(i, x); - } - - let mut it = xs.iter().enumerate(); - while let Some((i, &x)) = it.nth(0) { - assert_eq!(i, x); - } - - let mut it = xs.iter().enumerate(); - while let Some((i, &x)) = it.nth(1) { - assert_eq!(i, x); - } - - let (i, &x) = xs.iter().enumerate().nth(3).unwrap(); - assert_eq!(i, x); - assert_eq!(i, 3); -} - -#[test] -fn test_iterator_enumerate_nth_back() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().enumerate(); - while let Some((i, &x)) = it.nth_back(0) { - assert_eq!(i, x); - } - - let mut it = xs.iter().enumerate(); - while let Some((i, &x)) = it.nth_back(1) { - assert_eq!(i, x); - } - - let (i, &x) = xs.iter().enumerate().nth_back(3).unwrap(); - assert_eq!(i, x); - assert_eq!(i, 2); -} - -#[test] -fn test_iterator_enumerate_count() { - let xs = [0, 1, 2, 3, 4, 5]; - assert_eq!(xs.iter().enumerate().count(), 6); -} - -#[test] -fn test_iterator_enumerate_advance_by() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().enumerate(); - assert_eq!(it.advance_by(0), Ok(())); - assert_eq!(it.next(), Some((0, &0))); - assert_eq!(it.advance_by(1), Ok(())); - assert_eq!(it.next(), Some((2, &2))); - assert_eq!(it.advance_by(2), Ok(())); - assert_eq!(it.next(), Some((5, &5))); - assert_eq!(it.advance_by(1), Err(NonZero::new(1).unwrap())); - assert_eq!(it.next(), None); -} - -#[test] -fn test_iterator_enumerate_fold() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().enumerate(); - // steal a couple to get an interesting offset - assert_eq!(it.next(), Some((0, &0))); - assert_eq!(it.next(), Some((1, &1))); - let i = it.fold(2, |i, (j, &x)| { - assert_eq!(i, j); - assert_eq!(x, xs[j]); - i + 1 - }); - assert_eq!(i, xs.len()); - - let mut it = xs.iter().enumerate(); - assert_eq!(it.next(), Some((0, &0))); - let i = it.rfold(xs.len() - 1, |i, (j, &x)| { - assert_eq!(i, j); - assert_eq!(x, xs[j]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_enumerate_try_folds() { - let f = &|acc, (i, x)| usize::checked_add(2 * acc, x / (i + 1) + i); - assert_eq!((9..18).enumerate().try_fold(7, f), (0..9).map(|i| (i, i + 9)).try_fold(7, f)); - assert_eq!((9..18).enumerate().try_rfold(7, f), (0..9).map(|i| (i, i + 9)).try_rfold(7, f)); - - let mut iter = (100..200).enumerate(); - let f = &|acc, (i, x)| u8::checked_add(acc, u8::checked_div(x, i as u8 + 1)?); - assert_eq!(iter.try_fold(0, f), None); - assert_eq!(iter.next(), Some((7, 107))); - assert_eq!(iter.try_rfold(0, f), None); - assert_eq!(iter.next_back(), Some((11, 111))); -} - -#[test] -fn test_double_ended_enumerate() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().cloned().enumerate(); - assert_eq!(it.next(), Some((0, 1))); - assert_eq!(it.next(), Some((1, 2))); - assert_eq!(it.next_back(), Some((5, 6))); - assert_eq!(it.next_back(), Some((4, 5))); - assert_eq!(it.next_back(), Some((3, 4))); - assert_eq!(it.next_back(), Some((2, 3))); - assert_eq!(it.next(), None); -} diff --git a/library/core/tests/iter/adapters/filter.rs b/library/core/tests/iter/adapters/filter.rs deleted file mode 100644 index 167851e3333..00000000000 --- a/library/core/tests/iter/adapters/filter.rs +++ /dev/null @@ -1,65 +0,0 @@ -use core::iter::*; -use std::rc::Rc; - -#[test] -fn test_iterator_filter_count() { - let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5); -} - -#[test] -fn test_iterator_filter_fold() { - let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - let ys = [0, 2, 4, 6, 8]; - let it = xs.iter().filter(|&&x| x % 2 == 0); - let i = it.fold(0, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let it = xs.iter().filter(|&&x| x % 2 == 0); - let i = it.rfold(ys.len(), |i, &x| { - assert_eq!(x, ys[i - 1]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_filter_try_folds() { - fn p(&x: &i32) -> bool { - 0 <= x && x < 10 - } - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((-10..20).filter(p).try_fold(7, f), (0..10).try_fold(7, f)); - assert_eq!((-10..20).filter(p).try_rfold(7, f), (0..10).try_rfold(7, f)); - - let mut iter = (0..40).filter(|&x| x % 2 == 1); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(25)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(31)); -} - -#[test] -fn test_double_ended_filter() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().filter(|&x| *x & 1 == 0); - assert_eq!(it.next_back().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &4); - assert_eq!(it.next().unwrap(), &2); - assert_eq!(it.next_back(), None); -} - -#[test] -fn test_next_chunk_does_not_leak() { - let drop_witness: [_; 5] = std::array::from_fn(|_| Rc::new(())); - - let v = (0..5).map(|i| drop_witness[i].clone()).collect::>(); - let _ = v.into_iter().filter(|_| false).next_chunk::<1>(); - - for ref w in drop_witness { - assert_eq!(Rc::strong_count(w), 1); - } -} diff --git a/library/core/tests/iter/adapters/filter_map.rs b/library/core/tests/iter/adapters/filter_map.rs deleted file mode 100644 index 46738eda63f..00000000000 --- a/library/core/tests/iter/adapters/filter_map.rs +++ /dev/null @@ -1,50 +0,0 @@ -use core::iter::*; - -#[test] -fn test_filter_map() { - let it = (0..).step_by(1).take(10).filter_map(|x| if x % 2 == 0 { Some(x * x) } else { None }); - assert_eq!(it.collect::>(), [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]); -} - -#[test] -fn test_filter_map_fold() { - let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - let ys = [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]; - let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None }); - let i = it.fold(0, |i, x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None }); - let i = it.rfold(ys.len(), |i, x| { - assert_eq!(x, ys[i - 1]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_filter_map_try_folds() { - let mp = &|x| if 0 <= x && x < 10 { Some(x * 2) } else { None }; - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((-9..20).filter_map(mp).try_fold(7, f), (0..10).map(|x| 2 * x).try_fold(7, f)); - assert_eq!((-9..20).filter_map(mp).try_rfold(7, f), (0..10).map(|x| 2 * x).try_rfold(7, f)); - - let mut iter = (0..40).filter_map(|x| if x % 2 == 1 { None } else { Some(x * 2 + 10) }); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(38)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(78)); -} - -#[test] -fn test_double_ended_filter_map() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None }); - assert_eq!(it.next_back().unwrap(), 12); - assert_eq!(it.next_back().unwrap(), 8); - assert_eq!(it.next().unwrap(), 4); - assert_eq!(it.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/flat_map.rs b/library/core/tests/iter/adapters/flat_map.rs deleted file mode 100644 index ee945e69801..00000000000 --- a/library/core/tests/iter/adapters/flat_map.rs +++ /dev/null @@ -1,74 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_flat_map() { - let xs = [0, 3, 6]; - let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3)); - let mut i = 0; - for x in it { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} - -/// Tests `FlatMap::fold` with items already picked off the front and back, -/// to make sure all parts of the `FlatMap` are folded correctly. -#[test] -fn test_iterator_flat_map_fold() { - let xs = [0, 3, 6]; - let ys = [1, 2, 3, 4, 5, 6, 7]; - let mut it = xs.iter().flat_map(|&x| x..x + 3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next_back(), Some(8)); - let i = it.fold(0, |i, x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let mut it = xs.iter().flat_map(|&x| x..x + 3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next_back(), Some(8)); - let i = it.rfold(ys.len(), |i, x| { - assert_eq!(x, ys[i - 1]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_flat_map_try_folds() { - let f = &|acc, x| i32::checked_add(acc * 2 / 3, x); - let mr = &|x| (5 * x)..(5 * x + 5); - assert_eq!((0..10).flat_map(mr).try_fold(7, f), (0..50).try_fold(7, f)); - assert_eq!((0..10).flat_map(mr).try_rfold(7, f), (0..50).try_rfold(7, f)); - let mut iter = (0..10).flat_map(mr); - iter.next(); - iter.next_back(); // have front and back iters in progress - assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f)); - - let mut iter = (0..10).flat_map(|x| (4 * x)..(4 * x + 4)); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(17)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(35)); -} - -#[test] -fn test_double_ended_flat_map() { - let u = [0, 1]; - let v = [5, 6, 7, 8]; - let mut it = u.iter().flat_map(|x| &v[*x..v.len()]); - assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &5); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back(), None); - assert_eq!(it.next(), None); - assert_eq!(it.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs deleted file mode 100644 index 66b7b6cb563..00000000000 --- a/library/core/tests/iter/adapters/flatten.rs +++ /dev/null @@ -1,281 +0,0 @@ -use core::assert_eq; -use core::iter::*; -use core::num::NonZero; - -use super::*; - -#[test] -fn test_iterator_flatten() { - let xs = [0, 3, 6]; - let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten(); - let mut i = 0; - for x in it { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} - -/// Tests `Flatten::fold` with items already picked off the front and back, -/// to make sure all parts of the `Flatten` are folded correctly. -#[test] -fn test_iterator_flatten_fold() { - let xs = [0, 3, 6]; - let ys = [1, 2, 3, 4, 5, 6, 7]; - let mut it = xs.iter().map(|&x| x..x + 3).flatten(); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next_back(), Some(8)); - let i = it.fold(0, |i, x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let mut it = xs.iter().map(|&x| x..x + 3).flatten(); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next_back(), Some(8)); - let i = it.rfold(ys.len(), |i, x| { - assert_eq!(x, ys[i - 1]); - i - 1 - }); - assert_eq!(i, 0); -} - -#[test] -fn test_flatten_try_folds() { - let f = &|acc, x| i32::checked_add(acc * 2 / 3, x); - let mr = &|x| (5 * x)..(5 * x + 5); - assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f)); - assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f)); - let mut iter = (0..10).map(mr).flatten(); - iter.next(); - iter.next_back(); // have front and back iters in progress - assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f)); - - let mut iter = (0..10).map(|x| (4 * x)..(4 * x + 4)).flatten(); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(17)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(35)); -} - -#[test] -fn test_flatten_advance_by() { - let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); - - assert_eq!(it.advance_by(5), Ok(())); - assert_eq!(it.next(), Some(5)); - assert_eq!(it.advance_by(9), Ok(())); - assert_eq!(it.next(), Some(15)); - assert_eq!(it.advance_back_by(4), Ok(())); - assert_eq!(it.next_back(), Some(35)); - assert_eq!(it.advance_back_by(9), Ok(())); - assert_eq!(it.next_back(), Some(25)); - - assert_eq!(it.advance_by(usize::MAX), Err(NonZero::new(usize::MAX - 9).unwrap())); - assert_eq!(it.advance_back_by(usize::MAX), Err(NonZero::new(usize::MAX).unwrap())); - assert_eq!(it.advance_by(0), Ok(())); - assert_eq!(it.advance_back_by(0), Ok(())); - assert_eq!(it.size_hint(), (0, Some(0))); -} - -#[test] -fn test_flatten_non_fused_outer() { - let mut iter = NonFused::new(once(0..2)).flatten(); - - assert_eq!(iter.next_back(), Some(1)); - assert_eq!(iter.next(), Some(0)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut iter = NonFused::new(once(0..2)).flatten(); - - assert_eq!(iter.next(), Some(0)); - assert_eq!(iter.next_back(), Some(1)); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); -} - -#[test] -fn test_flatten_non_fused_inner() { - let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new); - - assert_eq!(iter.next_back(), Some(2)); - assert_eq!(iter.next(), Some(0)); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new); - - assert_eq!(iter.next(), Some(0)); - assert_eq!(iter.next_back(), Some(2)); - assert_eq!(iter.next_back(), Some(1)); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); -} - -#[test] -fn test_double_ended_flatten() { - let u = [0, 1]; - let v = [5, 6, 7, 8]; - let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten(); - assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &5); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &8); - assert_eq!(it.next().unwrap(), &6); - assert_eq!(it.next_back().unwrap(), &7); - assert_eq!(it.next_back(), None); - assert_eq!(it.next(), None); - assert_eq!(it.next_back(), None); -} - -#[test] -fn test_trusted_len_flatten() { - fn assert_trusted_len(_: &T) {} - let mut iter = IntoIterator::into_iter([[0; 3]; 4]).flatten(); - assert_trusted_len(&iter); - - assert_eq!(iter.size_hint(), (12, Some(12))); - iter.next(); - assert_eq!(iter.size_hint(), (11, Some(11))); - iter.next_back(); - assert_eq!(iter.size_hint(), (10, Some(10))); - - let iter = IntoIterator::into_iter([[(); usize::MAX]; 1]).flatten(); - assert_eq!(iter.size_hint(), (usize::MAX, Some(usize::MAX))); - - let iter = IntoIterator::into_iter([[(); usize::MAX]; 2]).flatten(); - assert_eq!(iter.size_hint(), (usize::MAX, None)); - - let mut a = [(); 10]; - let mut b = [(); 10]; - - let iter = IntoIterator::into_iter([&mut a, &mut b]).flatten(); - assert_trusted_len(&iter); - assert_eq!(iter.size_hint(), (20, Some(20))); - core::mem::drop(iter); - - let iter = IntoIterator::into_iter([&a, &b]).flatten(); - assert_trusted_len(&iter); - assert_eq!(iter.size_hint(), (20, Some(20))); - - let iter = [(), (), ()].iter().flat_map(|_| [(); 1000]); - assert_trusted_len(&iter); - assert_eq!(iter.size_hint(), (3000, Some(3000))); - - let iter = [(), ()].iter().flat_map(|_| &a); - assert_trusted_len(&iter); - assert_eq!(iter.size_hint(), (20, Some(20))); -} - -#[test] -fn test_flatten_count() { - let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); - - assert_eq!(it.clone().count(), 40); - assert_eq!(it.advance_by(5), Ok(())); - assert_eq!(it.clone().count(), 35); - assert_eq!(it.advance_back_by(5), Ok(())); - assert_eq!(it.clone().count(), 30); - assert_eq!(it.advance_by(10), Ok(())); - assert_eq!(it.clone().count(), 20); - assert_eq!(it.advance_back_by(8), Ok(())); - assert_eq!(it.clone().count(), 12); - assert_eq!(it.advance_by(4), Ok(())); - assert_eq!(it.clone().count(), 8); - assert_eq!(it.advance_back_by(5), Ok(())); - assert_eq!(it.clone().count(), 3); - assert_eq!(it.advance_by(3), Ok(())); - assert_eq!(it.clone().count(), 0); -} - -#[test] -fn test_flatten_last() { - let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); - - assert_eq!(it.clone().last(), Some(39)); - assert_eq!(it.advance_by(5), Ok(())); // 5..40 - assert_eq!(it.clone().last(), Some(39)); - assert_eq!(it.advance_back_by(5), Ok(())); // 5..35 - assert_eq!(it.clone().last(), Some(34)); - assert_eq!(it.advance_by(10), Ok(())); // 15..35 - assert_eq!(it.clone().last(), Some(34)); - assert_eq!(it.advance_back_by(8), Ok(())); // 15..27 - assert_eq!(it.clone().last(), Some(26)); - assert_eq!(it.advance_by(4), Ok(())); // 19..27 - assert_eq!(it.clone().last(), Some(26)); - assert_eq!(it.advance_back_by(5), Ok(())); // 19..22 - assert_eq!(it.clone().last(), Some(21)); - assert_eq!(it.advance_by(3), Ok(())); // 22..22 - assert_eq!(it.clone().last(), None); -} - -#[test] -fn test_flatten_one_shot() { - // This could be `filter_map`, but people often do flatten options. - let mut it = (0i8..10).flat_map(|i| NonZero::new(i % 7)); - assert_eq!(it.size_hint(), (0, Some(10))); - assert_eq!(it.clone().count(), 8); - assert_eq!(it.clone().last(), NonZero::new(2)); - - // sum -> fold - let sum: i8 = it.clone().map(|n| n.get()).sum(); - assert_eq!(sum, 24); - - // the product overflows at 6, remaining are 7,8,9 -> 1,2 - let one = NonZero::new(1i8).unwrap(); - let product = it.try_fold(one, |acc, x| acc.checked_mul(x)); - assert_eq!(product, None); - assert_eq!(it.size_hint(), (0, Some(3))); - assert_eq!(it.clone().count(), 2); - - assert_eq!(it.advance_by(0), Ok(())); - assert_eq!(it.clone().next(), NonZero::new(1)); - assert_eq!(it.advance_by(1), Ok(())); - assert_eq!(it.clone().next(), NonZero::new(2)); - assert_eq!(it.advance_by(100), Err(NonZero::new(99).unwrap())); - assert_eq!(it.next(), None); -} - -#[test] -fn test_flatten_one_shot_rev() { - let mut it = (0i8..10).flat_map(|i| NonZero::new(i % 7)).rev(); - assert_eq!(it.size_hint(), (0, Some(10))); - assert_eq!(it.clone().count(), 8); - assert_eq!(it.clone().last(), NonZero::new(1)); - - // sum -> Rev fold -> rfold - let sum: i8 = it.clone().map(|n| n.get()).sum(); - assert_eq!(sum, 24); - - // Rev try_fold -> try_rfold - // the product overflows at 4, remaining are 3,2,1,0 -> 3,2,1 - let one = NonZero::new(1i8).unwrap(); - let product = it.try_fold(one, |acc, x| acc.checked_mul(x)); - assert_eq!(product, None); - assert_eq!(it.size_hint(), (0, Some(4))); - assert_eq!(it.clone().count(), 3); - - // Rev advance_by -> advance_back_by - assert_eq!(it.advance_by(0), Ok(())); - assert_eq!(it.clone().next(), NonZero::new(3)); - assert_eq!(it.advance_by(1), Ok(())); - assert_eq!(it.clone().next(), NonZero::new(2)); - assert_eq!(it.advance_by(100), Err(NonZero::new(98).unwrap())); - assert_eq!(it.next(), None); -} - -#[test] -fn test_flatten_one_shot_arrays() { - let it = (0..10).flat_map(|i| [i]); - assert_eq!(it.size_hint(), (10, Some(10))); - assert_eq!(it.sum::(), 45); - - let mut it = (0..10).flat_map(|_| -> [i32; 0] { [] }); - assert_eq!(it.size_hint(), (0, Some(0))); - assert_eq!(it.next(), None); -} diff --git a/library/core/tests/iter/adapters/fuse.rs b/library/core/tests/iter/adapters/fuse.rs deleted file mode 100644 index f41b379b3ac..00000000000 --- a/library/core/tests/iter/adapters/fuse.rs +++ /dev/null @@ -1,75 +0,0 @@ -use core::iter::*; - -#[test] -fn test_fuse_nth() { - let xs = [0, 1, 2]; - let mut it = xs.iter(); - - assert_eq!(it.len(), 3); - assert_eq!(it.nth(2), Some(&2)); - assert_eq!(it.len(), 0); - assert_eq!(it.nth(2), None); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_fuse_last() { - let xs = [0, 1, 2]; - let it = xs.iter(); - - assert_eq!(it.len(), 3); - assert_eq!(it.last(), Some(&2)); -} - -#[test] -fn test_fuse_count() { - let xs = [0, 1, 2]; - let it = xs.iter(); - - assert_eq!(it.len(), 3); - assert_eq!(it.count(), 3); - // Can't check len now because count consumes. -} - -#[test] -fn test_fuse_fold() { - let xs = [0, 1, 2]; - let it = xs.iter(); // `FusedIterator` - let i = it.fuse().fold(0, |i, &x| { - assert_eq!(x, xs[i]); - i + 1 - }); - assert_eq!(i, xs.len()); - - let it = xs.iter(); // `FusedIterator` - let i = it.fuse().rfold(xs.len(), |i, &x| { - assert_eq!(x, xs[i - 1]); - i - 1 - }); - assert_eq!(i, 0); - - let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator` - let i = it.fuse().fold(0, |i, x| { - assert_eq!(x, xs[i]); - i + 1 - }); - assert_eq!(i, xs.len()); -} - -#[test] -fn test_fuse() { - let mut it = 0..3; - assert_eq!(it.len(), 3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.len(), 2); - assert_eq!(it.next(), Some(1)); - assert_eq!(it.len(), 1); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.len(), 0); - assert_eq!(it.next(), None); - assert_eq!(it.len(), 0); - assert_eq!(it.next(), None); - assert_eq!(it.len(), 0); - assert_eq!(it.next(), None); - assert_eq!(it.len(), 0); -} diff --git a/library/core/tests/iter/adapters/inspect.rs b/library/core/tests/iter/adapters/inspect.rs deleted file mode 100644 index 939e3a28a72..00000000000 --- a/library/core/tests/iter/adapters/inspect.rs +++ /dev/null @@ -1,38 +0,0 @@ -use core::iter::*; - -#[test] -fn test_inspect() { - let xs = [1, 2, 3, 4]; - let mut n = 0; - - let ys = xs.iter().cloned().inspect(|_| n += 1).collect::>(); - - assert_eq!(n, xs.len()); - assert_eq!(&xs[..], &ys[..]); -} - -#[test] -fn test_inspect_fold() { - let xs = [1, 2, 3, 4]; - let mut n = 0; - { - let it = xs.iter().inspect(|_| n += 1); - let i = it.fold(0, |i, &x| { - assert_eq!(x, xs[i]); - i + 1 - }); - assert_eq!(i, xs.len()); - } - assert_eq!(n, xs.len()); - - let mut n = 0; - { - let it = xs.iter().inspect(|_| n += 1); - let i = it.rfold(xs.len(), |i, &x| { - assert_eq!(x, xs[i - 1]); - i - 1 - }); - assert_eq!(i, 0); - } - assert_eq!(n, xs.len()); -} diff --git a/library/core/tests/iter/adapters/intersperse.rs b/library/core/tests/iter/adapters/intersperse.rs deleted file mode 100644 index 72ae59b6b2f..00000000000 --- a/library/core/tests/iter/adapters/intersperse.rs +++ /dev/null @@ -1,154 +0,0 @@ -use core::iter::*; - -#[test] -fn test_intersperse() { - let v = std::iter::empty().intersperse(0u32).collect::>(); - assert_eq!(v, vec![]); - - let v = std::iter::once(1).intersperse(0).collect::>(); - assert_eq!(v, vec![1]); - - let xs = ["a", "", "b", "c"]; - let v: Vec<&str> = xs.iter().map(|x| *x).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 test_intersperse_size_hint() { - let iter = std::iter::empty::().intersperse(0); - assert_eq!(iter.size_hint(), (0, Some(0))); - - let xs = ["a", "", "b", "c"]; - let mut iter = xs.iter().map(|x| *x).intersperse(", "); - assert_eq!(iter.size_hint(), (7, Some(7))); - - assert_eq!(iter.next(), Some("a")); - assert_eq!(iter.size_hint(), (6, Some(6))); - assert_eq!(iter.next(), Some(", ")); - assert_eq!(iter.size_hint(), (5, Some(5))); - - assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0))); -} - -#[test] -fn test_fold_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())); -} - -#[test] -fn test_try_fold_specialization_intersperse_ok() { - let mut iter = (1..2).intersperse(0); - iter.clone().try_for_each(|x| { - assert_eq!(Some(x), iter.next()); - Some(()) - }); - - let mut iter = (1..3).intersperse(0); - iter.clone().try_for_each(|x| { - assert_eq!(Some(x), iter.next()); - Some(()) - }); - - let mut iter = (1..4).intersperse(0); - iter.clone().try_for_each(|x| { - assert_eq!(Some(x), iter.next()); - Some(()) - }); -} - -#[test] -fn test_intersperse_with() { - #[derive(PartialEq, Debug)] - struct NotClone { - u: u32, - } - let r = [NotClone { u: 0 }, NotClone { u: 1 }] - .into_iter() - .intersperse_with(|| NotClone { u: 2 }) - .collect::>(); - assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]); - - let mut ctr = 100; - let separator = || { - ctr *= 2; - ctr - }; - let r = (0..3).intersperse_with(separator).collect::>(); - assert_eq!(r, vec![0, 200, 1, 400, 2]); -} - -#[test] -fn test_intersperse_fold() { - let v = (1..4).intersperse(9).fold(Vec::new(), |mut acc, x| { - acc.push(x); - acc - }); - assert_eq!(v.as_slice(), [1, 9, 2, 9, 3]); - - let mut iter = (1..4).intersperse(9); - assert_eq!(iter.next(), Some(1)); - let v = iter.fold(Vec::new(), |mut acc, x| { - acc.push(x); - acc - }); - assert_eq!(v.as_slice(), [9, 2, 9, 3]); - - struct NoneAtStart(i32); // Produces: None, Some(2), Some(3), None, ... - impl Iterator for NoneAtStart { - type Item = i32; - fn next(&mut self) -> Option { - self.0 += 1; - Some(self.0).filter(|i| i % 3 != 1) - } - } - - let v = NoneAtStart(0).intersperse(1000).fold(0, |a, b| a + b); - assert_eq!(v, 0); -} - -#[test] -fn test_intersperse_collect_string() { - let contents = [1, 2, 3]; - - let contents_string = contents - .into_iter() - .map(|id| id.to_string()) - .intersperse(", ".to_owned()) - .collect::(); - assert_eq!(contents_string, "1, 2, 3"); -} - -#[test] -fn test_try_fold_specialization_intersperse_err() { - let orig_iter = ["a", "b"].iter().copied().intersperse("-"); - - // Abort after the first item. - let mut iter = orig_iter.clone(); - iter.try_for_each(|_| None::<()>); - assert_eq!(iter.next(), Some("-")); - assert_eq!(iter.next(), Some("b")); - assert_eq!(iter.next(), None); - - // Abort after the second item. - let mut iter = orig_iter.clone(); - iter.try_for_each(|item| if item == "-" { None } else { Some(()) }); - assert_eq!(iter.next(), Some("b")); - assert_eq!(iter.next(), None); - - // Abort after the third item. - let mut iter = orig_iter.clone(); - iter.try_for_each(|item| if item == "b" { None } else { Some(()) }); - assert_eq!(iter.next(), None); -} diff --git a/library/core/tests/iter/adapters/map.rs b/library/core/tests/iter/adapters/map.rs deleted file mode 100644 index 77ce3819b32..00000000000 --- a/library/core/tests/iter/adapters/map.rs +++ /dev/null @@ -1,27 +0,0 @@ -use core::iter::*; - -#[test] -fn test_map_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((0..10).map(|x| x + 3).try_fold(7, f), (3..13).try_fold(7, f)); - assert_eq!((0..10).map(|x| x + 3).try_rfold(7, f), (3..13).try_rfold(7, f)); - - let mut iter = (0..40).map(|x| x + 10); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(20)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(46)); -} - -#[test] -fn test_double_ended_map() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut it = xs.iter().map(|&x| x * -1); - assert_eq!(it.next(), Some(-1)); - assert_eq!(it.next(), Some(-2)); - assert_eq!(it.next_back(), Some(-6)); - assert_eq!(it.next_back(), Some(-5)); - assert_eq!(it.next(), Some(-3)); - assert_eq!(it.next_back(), Some(-4)); - assert_eq!(it.next(), None); -} diff --git a/library/core/tests/iter/adapters/map_windows.rs b/library/core/tests/iter/adapters/map_windows.rs deleted file mode 100644 index b677f1cfd55..00000000000 --- a/library/core/tests/iter/adapters/map_windows.rs +++ /dev/null @@ -1,287 +0,0 @@ -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::SeqCst; - -#[cfg(not(panic = "abort"))] -mod drop_checks { - //! These tests mainly make sure the elements are correctly dropped. - - use std::sync::atomic::Ordering::SeqCst; - use std::sync::atomic::{AtomicBool, AtomicUsize}; - - #[derive(Debug)] - struct DropInfo { - dropped_twice: AtomicBool, - alive_count: AtomicUsize, - } - - impl DropInfo { - const fn new() -> Self { - Self { dropped_twice: AtomicBool::new(false), alive_count: AtomicUsize::new(0) } - } - - #[track_caller] - fn check(&self) { - assert!(!self.dropped_twice.load(SeqCst), "a value was dropped twice"); - assert_eq!(self.alive_count.load(SeqCst), 0); - } - } - - #[derive(Debug)] - struct DropCheck<'a> { - info: &'a DropInfo, - was_dropped: bool, - } - - impl<'a> DropCheck<'a> { - fn new(info: &'a DropInfo) -> Self { - info.alive_count.fetch_add(1, SeqCst); - - Self { info, was_dropped: false } - } - } - - impl Drop for DropCheck<'_> { - fn drop(&mut self) { - if self.was_dropped { - self.info.dropped_twice.store(true, SeqCst); - } - self.was_dropped = true; - - self.info.alive_count.fetch_sub(1, SeqCst); - } - } - - fn iter(info: &DropInfo, len: usize, panic_at: usize) -> impl Iterator> { - (0..len).map(move |i| { - if i == panic_at { - panic!("intended panic"); - } - DropCheck::new(info) - }) - } - - #[track_caller] - fn check(len: usize, panic_at: usize) { - check_drops(|info| { - iter(info, len, panic_at).map_windows(|_: &[_; N]| {}).last(); - }); - } - - #[track_caller] - fn check_drops(f: impl FnOnce(&DropInfo)) { - let info = DropInfo::new(); - let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - f(&info); - })); - info.check(); - } - - #[test] - fn no_iter_panic_n1() { - check::<1>(0, 100); - check::<1>(1, 100); - check::<1>(2, 100); - check::<1>(13, 100); - } - - #[test] - fn no_iter_panic_n2() { - check::<2>(0, 100); - check::<2>(1, 100); - check::<2>(2, 100); - check::<2>(3, 100); - check::<2>(13, 100); - } - - #[test] - fn no_iter_panic_n5() { - check::<5>(0, 100); - check::<5>(1, 100); - check::<5>(2, 100); - check::<5>(13, 100); - check::<5>(30, 100); - } - - #[test] - fn panic_in_first_batch() { - check::<1>(7, 0); - - check::<2>(7, 0); - check::<2>(7, 1); - - check::<3>(7, 0); - check::<3>(7, 1); - check::<3>(7, 2); - } - - #[test] - fn panic_in_middle() { - check::<1>(7, 1); - check::<1>(7, 5); - check::<1>(7, 6); - - check::<2>(7, 2); - check::<2>(7, 5); - check::<2>(7, 6); - - check::<5>(13, 5); - check::<5>(13, 8); - check::<5>(13, 12); - } - - #[test] - fn len_equals_n() { - check::<1>(1, 100); - check::<1>(1, 0); - - check::<2>(2, 100); - check::<2>(2, 0); - check::<2>(2, 1); - - check::<5>(5, 100); - check::<5>(5, 0); - check::<5>(5, 1); - check::<5>(5, 4); - } -} - -#[test] -fn output_n1() { - assert_eq!("".chars().map_windows(|[c]| *c).collect::>(), vec![]); - assert_eq!("x".chars().map_windows(|[c]| *c).collect::>(), vec!['x']); - assert_eq!("abcd".chars().map_windows(|[c]| *c).collect::>(), vec!['a', 'b', 'c', 'd']); -} - -#[test] -fn output_n2() { - assert_eq!( - "".chars().map_windows(|a: &[_; 2]| *a).collect::>(), - >::new(), - ); - assert_eq!("ab".chars().map_windows(|a: &[_; 2]| *a).collect::>(), vec![['a', 'b']]); - assert_eq!("abcd".chars().map_windows(|a: &[_; 2]| *a).collect::>(), vec![ - ['a', 'b'], - ['b', 'c'], - ['c', 'd'] - ],); -} - -#[test] -fn test_case_from_pr_82413_comment() { - for () in std::iter::repeat("0".to_owned()).map_windows(|_: &[_; 3]| {}).take(4) {} -} - -#[test] -#[should_panic = "array in `Iterator::map_windows` must contain more than 0 elements"] -fn check_zero_window() { - let _ = std::iter::repeat(0).map_windows(|_: &[_; 0]| ()); -} - -#[test] -fn test_zero_sized_type() { - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - struct Data; - let data: Vec<_> = - std::iter::repeat(Data).take(10).map_windows(|arr: &[Data; 5]| *arr).collect(); - assert_eq!(data, [[Data; 5]; 6]); -} - -#[test] -#[should_panic = "array size of `Iterator::map_windows` is too large"] -fn test_too_large_array_size() { - let _ = std::iter::repeat(()).map_windows(|arr: &[(); usize::MAX]| *arr); -} - -#[test] -fn test_laziness() { - let counter = AtomicUsize::new(0); - let mut iter = (0..5) - .inspect(|_| { - counter.fetch_add(1, SeqCst); - }) - .map_windows(|arr: &[i32; 2]| *arr); - assert_eq!(counter.load(SeqCst), 0); - - assert_eq!(iter.next(), Some([0, 1])); - // The first iteration consumes N items (N = 2). - assert_eq!(counter.load(SeqCst), 2); - - assert_eq!(iter.next(), Some([1, 2])); - assert_eq!(counter.load(SeqCst), 3); - - assert_eq!(iter.next(), Some([2, 3])); - assert_eq!(counter.load(SeqCst), 4); - - assert_eq!(iter.next(), Some([3, 4])); - assert_eq!(counter.load(SeqCst), 5); - - assert_eq!(iter.next(), None); - assert_eq!(counter.load(SeqCst), 5); -} - -#[test] -fn test_size_hint() { - struct SizeHintCheckHelper((usize, Option)); - - impl Iterator for SizeHintCheckHelper { - type Item = i32; - - fn next(&mut self) -> Option { - let (ref mut lo, ref mut hi) = self.0; - let next = (*hi != Some(0)).then_some(0); - *lo = lo.saturating_sub(1); - if let Some(hi) = hi { - *hi = hi.saturating_sub(1); - } - next - } - - fn size_hint(&self) -> (usize, Option) { - self.0 - } - } - - fn check_size_hint( - size_hint: (usize, Option), - mut mapped_size_hint: (usize, Option), - ) { - let mut iter = SizeHintCheckHelper(size_hint); - let mut mapped_iter = iter.by_ref().map_windows(|_: &[_; N]| ()); - while mapped_iter.size_hint().0 > 0 { - assert_eq!(mapped_iter.size_hint(), mapped_size_hint); - assert!(mapped_iter.next().is_some()); - mapped_size_hint.0 -= 1; - mapped_size_hint.1 = mapped_size_hint.1.map(|hi| hi.saturating_sub(1)); - } - } - - check_size_hint::<1>((0, None), (0, None)); - check_size_hint::<1>((0, Some(0)), (0, Some(0))); - check_size_hint::<1>((0, Some(2)), (0, Some(2))); - check_size_hint::<1>((1, None), (1, None)); - check_size_hint::<1>((1, Some(1)), (1, Some(1))); - check_size_hint::<1>((1, Some(4)), (1, Some(4))); - check_size_hint::<1>((5, None), (5, None)); - check_size_hint::<1>((5, Some(5)), (5, Some(5))); - check_size_hint::<1>((5, Some(10)), (5, Some(10))); - - check_size_hint::<2>((0, None), (0, None)); - check_size_hint::<2>((0, Some(0)), (0, Some(0))); - check_size_hint::<2>((0, Some(2)), (0, Some(1))); - check_size_hint::<2>((1, None), (0, None)); - check_size_hint::<2>((1, Some(1)), (0, Some(0))); - check_size_hint::<2>((1, Some(4)), (0, Some(3))); - check_size_hint::<2>((5, None), (4, None)); - check_size_hint::<2>((5, Some(5)), (4, Some(4))); - check_size_hint::<2>((5, Some(10)), (4, Some(9))); - - check_size_hint::<5>((0, None), (0, None)); - check_size_hint::<5>((0, Some(0)), (0, Some(0))); - check_size_hint::<5>((0, Some(2)), (0, Some(0))); - check_size_hint::<5>((1, None), (0, None)); - check_size_hint::<5>((1, Some(1)), (0, Some(0))); - check_size_hint::<5>((1, Some(4)), (0, Some(0))); - check_size_hint::<5>((5, None), (1, None)); - check_size_hint::<5>((5, Some(5)), (1, Some(1))); - check_size_hint::<5>((5, Some(10)), (1, Some(6))); -} diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs deleted file mode 100644 index dedb4c0a9dd..00000000000 --- a/library/core/tests/iter/adapters/mod.rs +++ /dev/null @@ -1,210 +0,0 @@ -mod array_chunks; -mod by_ref_sized; -mod chain; -mod cloned; -mod copied; -mod cycle; -mod enumerate; -mod filter; -mod filter_map; -mod flat_map; -mod flatten; -mod fuse; -mod inspect; -mod intersperse; -mod map; -mod map_windows; -mod peekable; -mod scan; -mod skip; -mod skip_while; -mod step_by; -mod take; -mod take_while; -mod zip; - -use core::cell::Cell; - -/// An iterator that panics whenever `next` or `next_back` is called -/// after `None` has already been returned. This does not violate -/// `Iterator`'s contract. Used to test that iterator adapters don't -/// poll their inner iterators after exhausting them. -pub struct NonFused { - iter: I, - done: bool, -} - -impl NonFused { - pub fn new(iter: I) -> Self { - Self { iter, done: false } - } -} - -impl Iterator for NonFused -where - I: Iterator, -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - assert!(!self.done, "this iterator has already returned None"); - self.iter.next().or_else(|| { - self.done = true; - None - }) - } -} - -impl DoubleEndedIterator for NonFused -where - I: DoubleEndedIterator, -{ - fn next_back(&mut self) -> Option { - assert!(!self.done, "this iterator has already returned None"); - self.iter.next_back().or_else(|| { - self.done = true; - None - }) - } -} - -/// An iterator wrapper that panics whenever `next` or `next_back` is called -/// after `None` has been returned. -pub struct Unfuse { - iter: I, - exhausted: bool, -} - -impl Unfuse { - pub fn new(iter: T) -> Self - where - T: IntoIterator, - { - Self { iter: iter.into_iter(), exhausted: false } - } -} - -impl Iterator for Unfuse -where - I: Iterator, -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - assert!(!self.exhausted); - let next = self.iter.next(); - self.exhausted = next.is_none(); - next - } -} - -impl DoubleEndedIterator for Unfuse -where - I: DoubleEndedIterator, -{ - fn next_back(&mut self) -> Option { - assert!(!self.exhausted); - let next = self.iter.next_back(); - self.exhausted = next.is_none(); - next - } -} - -pub struct Toggle { - is_empty: bool, -} - -impl Iterator for Toggle { - type Item = (); - - // alternates between `None` and `Some(())` - fn next(&mut self) -> Option { - if self.is_empty { - self.is_empty = false; - None - } else { - self.is_empty = true; - Some(()) - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.is_empty { (0, Some(0)) } else { (1, Some(1)) } - } -} - -impl DoubleEndedIterator for Toggle { - fn next_back(&mut self) -> Option { - self.next() - } -} - -/// This is an iterator that follows the Iterator contract, -/// but it is not fused. After having returned None once, it will start -/// producing elements if .next() is called again. -pub struct CycleIter<'a, T> { - index: usize, - data: &'a [T], -} - -impl<'a, T> CycleIter<'a, T> { - pub fn new(data: &'a [T]) -> Self { - Self { index: 0, data } - } -} - -impl<'a, T> Iterator for CycleIter<'a, T> { - type Item = &'a T; - fn next(&mut self) -> Option { - let elt = self.data.get(self.index); - self.index += 1; - self.index %= 1 + self.data.len(); - elt - } -} - -#[derive(Debug)] -struct CountClone(Cell); - -impl CountClone { - pub fn new() -> Self { - Self(Cell::new(0)) - } -} - -impl PartialEq for CountClone { - fn eq(&self, rhs: &i32) -> bool { - self.0.get() == *rhs - } -} - -impl Clone for CountClone { - fn clone(&self) -> Self { - let ret = CountClone(self.0.clone()); - let n = self.0.get(); - self.0.set(n + 1); - ret - } -} - -#[derive(Debug, Clone)] -struct CountDrop<'a> { - dropped: bool, - count: &'a Cell, -} - -impl<'a> CountDrop<'a> { - pub fn new(count: &'a Cell) -> Self { - Self { dropped: false, count } - } -} - -impl Drop for CountDrop<'_> { - fn drop(&mut self) { - if self.dropped { - panic!("double drop"); - } - self.dropped = true; - self.count.set(self.count.get() + 1); - } -} diff --git a/library/core/tests/iter/adapters/peekable.rs b/library/core/tests/iter/adapters/peekable.rs deleted file mode 100644 index 7f4341b8902..00000000000 --- a/library/core/tests/iter/adapters/peekable.rs +++ /dev/null @@ -1,273 +0,0 @@ -use core::iter::*; - -use super::*; - -#[test] -fn test_iterator_peekable() { - let xs = vec![0, 1, 2, 3, 4, 5]; - - let mut it = xs.iter().cloned().peekable(); - assert_eq!(it.len(), 6); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 6); - assert_eq!(it.next().unwrap(), 0); - assert_eq!(it.len(), 5); - assert_eq!(it.next().unwrap(), 1); - assert_eq!(it.len(), 4); - assert_eq!(it.next().unwrap(), 2); - assert_eq!(it.len(), 3); - assert_eq!(it.peek().unwrap(), &3); - assert_eq!(it.len(), 3); - assert_eq!(it.peek().unwrap(), &3); - assert_eq!(it.len(), 3); - assert_eq!(it.next().unwrap(), 3); - assert_eq!(it.len(), 2); - assert_eq!(it.next().unwrap(), 4); - assert_eq!(it.len(), 1); - assert_eq!(it.peek().unwrap(), &5); - assert_eq!(it.len(), 1); - assert_eq!(it.next().unwrap(), 5); - assert_eq!(it.len(), 0); - assert!(it.peek().is_none()); - assert_eq!(it.len(), 0); - assert!(it.next().is_none()); - assert_eq!(it.len(), 0); - - let mut it = xs.iter().cloned().peekable(); - assert_eq!(it.len(), 6); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 6); - assert_eq!(it.next_back().unwrap(), 5); - assert_eq!(it.len(), 5); - assert_eq!(it.next_back().unwrap(), 4); - assert_eq!(it.len(), 4); - assert_eq!(it.next_back().unwrap(), 3); - assert_eq!(it.len(), 3); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 3); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 3); - assert_eq!(it.next_back().unwrap(), 2); - assert_eq!(it.len(), 2); - assert_eq!(it.next_back().unwrap(), 1); - assert_eq!(it.len(), 1); - assert_eq!(it.peek().unwrap(), &0); - assert_eq!(it.len(), 1); - assert_eq!(it.next_back().unwrap(), 0); - assert_eq!(it.len(), 0); - assert!(it.peek().is_none()); - assert_eq!(it.len(), 0); - assert!(it.next_back().is_none()); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_iterator_peekable_count() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [10]; - let zs: [i32; 0] = []; - - assert_eq!(xs.iter().peekable().count(), 6); - - let mut it = xs.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - assert_eq!(it.count(), 6); - - assert_eq!(ys.iter().peekable().count(), 1); - - let mut it = ys.iter().peekable(); - assert_eq!(it.peek(), Some(&&10)); - assert_eq!(it.count(), 1); - - assert_eq!(zs.iter().peekable().count(), 0); - - let mut it = zs.iter().peekable(); - assert_eq!(it.peek(), None); -} - -#[test] -fn test_iterator_peekable_nth() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().peekable(); - - assert_eq!(it.peek(), Some(&&0)); - assert_eq!(it.nth(0), Some(&0)); - assert_eq!(it.peek(), Some(&&1)); - assert_eq!(it.nth(1), Some(&2)); - assert_eq!(it.peek(), Some(&&3)); - assert_eq!(it.nth(2), Some(&5)); - assert_eq!(it.next(), None); -} - -#[test] -fn test_iterator_peekable_last() { - let xs = [0, 1, 2, 3, 4, 5]; - let ys = [0]; - - let mut it = xs.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - assert_eq!(it.last(), Some(&5)); - - let mut it = ys.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - assert_eq!(it.last(), Some(&0)); - - let mut it = ys.iter().peekable(); - assert_eq!(it.next(), Some(&0)); - assert_eq!(it.peek(), None); - assert_eq!(it.last(), None); -} - -#[test] -fn test_iterator_peekable_fold() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - let i = it.fold(0, |i, &x| { - assert_eq!(x, xs[i]); - i + 1 - }); - assert_eq!(i, xs.len()); -} - -#[test] -fn test_iterator_peekable_rfold() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().peekable(); - assert_eq!(it.peek(), Some(&&0)); - let i = it.rfold(0, |i, &x| { - assert_eq!(x, xs[xs.len() - 1 - i]); - i + 1 - }); - assert_eq!(i, xs.len()); -} - -#[test] -fn test_iterator_peekable_next_if_eq() { - // first, try on references - let xs = ["Heart", "of", "Gold"]; - let mut it = xs.into_iter().peekable(); - // try before `peek()` - assert_eq!(it.next_if_eq(&"trillian"), None); - assert_eq!(it.next_if_eq(&"Heart"), Some("Heart")); - // try after peek() - assert_eq!(it.peek(), Some(&"of")); - assert_eq!(it.next_if_eq(&"of"), Some("of")); - assert_eq!(it.next_if_eq(&"zaphod"), None); - // make sure `next()` still behaves - assert_eq!(it.next(), Some("Gold")); - - // make sure comparison works for owned values - let xs = [String::from("Ludicrous"), "speed".into()]; - let mut it = xs.into_iter().peekable(); - // make sure basic functionality works - assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into())); - assert_eq!(it.next_if_eq("speed"), Some("speed".into())); - assert_eq!(it.next_if_eq(""), None); -} - -#[test] -fn test_iterator_peekable_mut() { - let mut it = [1, 2, 3].into_iter().peekable(); - if let Some(p) = it.peek_mut() { - if *p == 1 { - *p = 5; - } - } - assert_eq!(it.collect::>(), vec![5, 2, 3]); -} - -#[test] -fn test_iterator_peekable_remember_peek_none_1() { - // Check that the loop using .peek() terminates - let data = [1, 2, 3]; - let mut iter = CycleIter::new(&data).peekable(); - - let mut n = 0; - while let Some(_) = iter.next() { - let is_the_last = iter.peek().is_none(); - assert_eq!(is_the_last, n == data.len() - 1); - n += 1; - if n > data.len() { - break; - } - } - assert_eq!(n, data.len()); -} - -#[test] -fn test_iterator_peekable_remember_peek_none_2() { - let data = [0]; - let mut iter = CycleIter::new(&data).peekable(); - iter.next(); - assert_eq!(iter.peek(), None); - assert_eq!(iter.last(), None); -} - -#[test] -fn test_iterator_peekable_remember_peek_none_3() { - let data = [0]; - let mut iter = CycleIter::new(&data).peekable(); - iter.peek(); - assert_eq!(iter.nth(0), Some(&0)); - - let mut iter = CycleIter::new(&data).peekable(); - iter.next(); - assert_eq!(iter.peek(), None); - assert_eq!(iter.nth(0), None); -} - -#[test] -fn test_peek_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - - assert_eq!((1..20).peekable().try_fold(7, f), (1..20).try_fold(7, f)); - assert_eq!((1..20).peekable().try_rfold(7, f), (1..20).try_rfold(7, f)); - - let mut iter = (1..20).peekable(); - assert_eq!(iter.peek(), Some(&1)); - assert_eq!(iter.try_fold(7, f), (1..20).try_fold(7, f)); - - let mut iter = (1..20).peekable(); - assert_eq!(iter.peek(), Some(&1)); - assert_eq!(iter.try_rfold(7, f), (1..20).try_rfold(7, f)); - - let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable(); - assert_eq!(iter.peek(), Some(&100)); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.peek(), Some(&40)); - - let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable(); - assert_eq!(iter.peek(), Some(&100)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.peek(), Some(&100)); - assert_eq!(iter.next_back(), Some(50)); - - let mut iter = (2..5).peekable(); - assert_eq!(iter.peek(), Some(&2)); - assert_eq!(iter.try_for_each(Err), Err(2)); - assert_eq!(iter.peek(), Some(&3)); - assert_eq!(iter.try_for_each(Err), Err(3)); - assert_eq!(iter.peek(), Some(&4)); - assert_eq!(iter.try_for_each(Err), Err(4)); - assert_eq!(iter.peek(), None); - assert_eq!(iter.try_for_each(Err), Ok(())); - - let mut iter = (2..5).peekable(); - assert_eq!(iter.peek(), Some(&2)); - assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(4)); - assert_eq!(iter.peek(), Some(&2)); - assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(3)); - assert_eq!(iter.peek(), Some(&2)); - assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(2)); - assert_eq!(iter.peek(), None); - assert_eq!(iter.try_rfold((), |(), x| Err(x)), Ok(())); -} - -#[test] -fn test_peekable_non_fused() { - let mut iter = NonFused::new(empty::()).peekable(); - - assert_eq!(iter.peek(), None); - assert_eq!(iter.next_back(), None); -} diff --git a/library/core/tests/iter/adapters/scan.rs b/library/core/tests/iter/adapters/scan.rs deleted file mode 100644 index 1d28ca6b7fd..00000000000 --- a/library/core/tests/iter/adapters/scan.rs +++ /dev/null @@ -1,20 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_scan() { - // test the type inference - fn add(old: &mut isize, new: &usize) -> Option { - *old += *new as isize; - Some(*old as f64) - } - let xs = [0, 1, 2, 3, 4]; - let ys = [0f64, 1.0, 3.0, 6.0, 10.0]; - - let it = xs.iter().scan(0, add); - let mut i = 0; - for x in it { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs deleted file mode 100644 index 8d5d06ad9fb..00000000000 --- a/library/core/tests/iter/adapters/skip.rs +++ /dev/null @@ -1,238 +0,0 @@ -use core::iter::*; -use core::num::NonZero; - -use super::Unfuse; - -#[test] -fn test_iterator_skip() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - let ys = [13, 15, 16, 17, 19, 20, 30]; - let mut it = xs.iter().skip(5); - let mut i = 0; - while let Some(&x) = it.next() { - assert_eq!(x, ys[i]); - i += 1; - assert_eq!(it.len(), xs.len() - 5 - i); - } - assert_eq!(i, ys.len()); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_iterator_skip_doubleended() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - let mut it = xs.iter().rev().skip(5); - assert_eq!(it.next(), Some(&15)); - assert_eq!(it.by_ref().rev().next(), Some(&0)); - assert_eq!(it.next(), Some(&13)); - assert_eq!(it.by_ref().rev().next(), Some(&1)); - assert_eq!(it.next(), Some(&5)); - assert_eq!(it.by_ref().rev().next(), Some(&2)); - assert_eq!(it.next(), Some(&3)); - assert_eq!(it.next(), None); - let mut it = xs.iter().rev().skip(5).rev(); - assert_eq!(it.next(), Some(&0)); - assert_eq!(it.rev().next(), Some(&15)); - let mut it_base = xs.iter(); - { - let mut it = it_base.by_ref().skip(5).rev(); - assert_eq!(it.next(), Some(&30)); - assert_eq!(it.next(), Some(&20)); - assert_eq!(it.next(), Some(&19)); - assert_eq!(it.next(), Some(&17)); - assert_eq!(it.next(), Some(&16)); - assert_eq!(it.next(), Some(&15)); - assert_eq!(it.next(), Some(&13)); - assert_eq!(it.next(), None); - } - // make sure the skipped parts have not been consumed - assert_eq!(it_base.next(), Some(&0)); - assert_eq!(it_base.next(), Some(&1)); - assert_eq!(it_base.next(), Some(&2)); - assert_eq!(it_base.next(), Some(&3)); - assert_eq!(it_base.next(), Some(&5)); - assert_eq!(it_base.next(), None); - let it = xs.iter().skip(5).rev(); - assert_eq!(it.last(), Some(&13)); -} - -#[test] -fn test_iterator_skip_nth() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - - let mut it = xs.iter().skip(0); - assert_eq!(it.nth(0), Some(&0)); - assert_eq!(it.nth(1), Some(&2)); - - let mut it = xs.iter().skip(5); - assert_eq!(it.nth(0), Some(&13)); - assert_eq!(it.nth(1), Some(&16)); - - let mut it = xs.iter().skip(12); - assert_eq!(it.nth(0), None); -} - -#[test] -fn test_skip_advance_by() { - assert_eq!((0..0).skip(10).advance_by(0), Ok(())); - assert_eq!((0..0).skip(10).advance_by(1), Err(NonZero::new(1).unwrap())); - assert_eq!( - (0u128..(usize::MAX as u128) + 1).skip(usize::MAX - 10).advance_by(usize::MAX - 5), - Err(NonZero::new(usize::MAX - 16).unwrap()) - ); - assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), Ok(())); - - assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZero::new(9).unwrap())); - assert_eq!((0..0).skip(1).advance_back_by(0), Ok(())); -} - -#[test] -fn test_iterator_skip_count() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - - assert_eq!(xs.iter().skip(0).count(), 12); - assert_eq!(xs.iter().skip(1).count(), 11); - assert_eq!(xs.iter().skip(11).count(), 1); - assert_eq!(xs.iter().skip(12).count(), 0); - assert_eq!(xs.iter().skip(13).count(), 0); -} - -#[test] -fn test_iterator_skip_last() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - - assert_eq!(xs.iter().skip(0).last(), Some(&30)); - assert_eq!(xs.iter().skip(1).last(), Some(&30)); - assert_eq!(xs.iter().skip(11).last(), Some(&30)); - assert_eq!(xs.iter().skip(12).last(), None); - assert_eq!(xs.iter().skip(13).last(), None); - - let mut it = xs.iter().skip(5); - assert_eq!(it.next(), Some(&13)); - assert_eq!(it.last(), Some(&30)); -} - -#[test] -fn test_iterator_skip_fold() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - let ys = [13, 15, 16, 17, 19, 20, 30]; - - let it = xs.iter().skip(5); - let i = it.fold(0, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let mut it = xs.iter().skip(5); - assert_eq!(it.next(), Some(&ys[0])); // process skips before folding - let i = it.fold(1, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let it = xs.iter().skip(5); - let i = it.rfold(ys.len(), |i, &x| { - let i = i - 1; - assert_eq!(x, ys[i]); - i - }); - assert_eq!(i, 0); - - let mut it = xs.iter().skip(5); - assert_eq!(it.next(), Some(&ys[0])); // process skips before folding - let i = it.rfold(ys.len(), |i, &x| { - let i = i - 1; - assert_eq!(x, ys[i]); - i - }); - assert_eq!(i, 1); -} - -#[test] -fn test_skip_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((1..20).skip(9).try_fold(7, f), (10..20).try_fold(7, f)); - assert_eq!((1..20).skip(9).try_rfold(7, f), (10..20).try_rfold(7, f)); - - let mut iter = (0..30).skip(10); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(20)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(24)); -} - -#[test] -fn test_skip_nth_back() { - let xs = [0, 1, 2, 3, 4, 5]; - let mut it = xs.iter().skip(2); - assert_eq!(it.nth_back(0), Some(&5)); - assert_eq!(it.nth_back(1), Some(&3)); - assert_eq!(it.nth_back(0), Some(&2)); - assert_eq!(it.nth_back(0), None); - - let ys = [2, 3, 4, 5]; - let mut ity = ys.iter(); - let mut it = xs.iter().skip(2); - assert_eq!(it.nth_back(1), ity.nth_back(1)); - assert_eq!(it.clone().nth(0), ity.clone().nth(0)); - assert_eq!(it.nth_back(0), ity.nth_back(0)); - assert_eq!(it.clone().nth(0), ity.clone().nth(0)); - assert_eq!(it.nth_back(0), ity.nth_back(0)); - assert_eq!(it.clone().nth(0), ity.clone().nth(0)); - assert_eq!(it.nth_back(0), ity.nth_back(0)); - assert_eq!(it.clone().nth(0), ity.clone().nth(0)); - - let mut it = xs.iter().skip(2); - assert_eq!(it.nth_back(4), None); - assert_eq!(it.nth_back(0), None); - - let mut it = xs.iter(); - it.by_ref().skip(2).nth_back(3); - assert_eq!(it.next_back(), Some(&1)); - - let mut it = xs.iter(); - it.by_ref().skip(2).nth_back(10); - assert_eq!(it.next_back(), Some(&1)); -} - -#[test] -fn test_skip_non_fused() { - let non_fused = Unfuse::new(0..10); - - // `Skip` would previously exhaust the iterator in this `next` call and then erroneously try to - // advance it further. `Unfuse` tests that this doesn't happen by panicking in that scenario. - let _ = non_fused.skip(20).next(); -} - -#[test] -fn test_skip_non_fused_nth_overflow() { - let non_fused = Unfuse::new(0..10); - - // Ensures that calling skip and `nth` where the sum would overflow does not fail for non-fused - // iterators. - let _ = non_fused.skip(20).nth(usize::MAX); -} - -#[test] -fn test_skip_overflow_wrapping() { - // Test to ensure even on overflowing on `skip+nth` the correct amount of elements are yielded. - struct WrappingIterator(usize); - - impl Iterator for WrappingIterator { - type Item = usize; - - fn next(&mut self) -> core::option::Option { - ::nth(self, 0) - } - - fn nth(&mut self, nth: usize) -> core::option::Option { - self.0 = self.0.wrapping_add(nth.wrapping_add(1)); - Some(self.0) - } - } - - let wrap = WrappingIterator(0); - assert_eq!(wrap.skip(20).nth(usize::MAX), Some(20)); -} diff --git a/library/core/tests/iter/adapters/skip_while.rs b/library/core/tests/iter/adapters/skip_while.rs deleted file mode 100644 index 929d4f6e64f..00000000000 --- a/library/core/tests/iter/adapters/skip_while.rs +++ /dev/null @@ -1,50 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_skip_while() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [15, 16, 17, 19]; - let it = xs.iter().skip_while(|&x| *x < 15); - let mut i = 0; - for x in it { - assert_eq!(*x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} - -#[test] -fn test_iterator_skip_while_fold() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [15, 16, 17, 19]; - let it = xs.iter().skip_while(|&x| *x < 15); - let i = it.fold(0, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); - - let mut it = xs.iter().skip_while(|&x| *x < 15); - assert_eq!(it.next(), Some(&ys[0])); // process skips before folding - let i = it.fold(1, |i, &x| { - assert_eq!(x, ys[i]); - i + 1 - }); - assert_eq!(i, ys.len()); -} - -#[test] -fn test_skip_while_try_fold() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - fn p(&x: &i32) -> bool { - (x % 10) <= 5 - } - assert_eq!((1..20).skip_while(p).try_fold(7, f), (6..20).try_fold(7, f)); - let mut iter = (1..20).skip_while(p); - assert_eq!(iter.nth(5), Some(11)); - assert_eq!(iter.try_fold(7, f), (12..20).try_fold(7, f)); - - let mut iter = (0..50).skip_while(|&x| (x % 20) < 15); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(23)); -} diff --git a/library/core/tests/iter/adapters/step_by.rs b/library/core/tests/iter/adapters/step_by.rs deleted file mode 100644 index 6f3300e7a88..00000000000 --- a/library/core/tests/iter/adapters/step_by.rs +++ /dev/null @@ -1,301 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_step_by() { - // Identity - let mut it = (0..).step_by(1).take(3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next(), Some(1)); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.next(), None); - - let mut it = (0..).step_by(3).take(4); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next(), Some(3)); - assert_eq!(it.next(), Some(6)); - assert_eq!(it.next(), Some(9)); - assert_eq!(it.next(), None); - - let mut it = (0..3).step_by(1); - assert_eq!(it.next_back(), Some(2)); - assert_eq!(it.next_back(), Some(1)); - assert_eq!(it.next_back(), Some(0)); - assert_eq!(it.next_back(), None); - - let mut it = (0..11).step_by(3); - assert_eq!(it.next_back(), Some(9)); - assert_eq!(it.next_back(), Some(6)); - assert_eq!(it.next_back(), Some(3)); - assert_eq!(it.next_back(), Some(0)); - assert_eq!(it.next_back(), None); -} - -#[test] -fn test_iterator_step_by_nth() { - let mut it = (0..16).step_by(5); - assert_eq!(it.nth(0), Some(0)); - assert_eq!(it.nth(0), Some(5)); - assert_eq!(it.nth(0), Some(10)); - assert_eq!(it.nth(0), Some(15)); - assert_eq!(it.nth(0), None); - - let it = (0..18).step_by(5); - assert_eq!(it.clone().nth(0), Some(0)); - assert_eq!(it.clone().nth(1), Some(5)); - assert_eq!(it.clone().nth(2), Some(10)); - assert_eq!(it.clone().nth(3), Some(15)); - assert_eq!(it.clone().nth(4), None); - assert_eq!(it.clone().nth(42), None); -} - -#[test] -#[allow(non_local_definitions)] -fn test_iterator_step_by_nth_overflow() { - #[cfg(target_pointer_width = "16")] - type Bigger = u32; - #[cfg(target_pointer_width = "32")] - type Bigger = u64; - #[cfg(target_pointer_width = "64")] - type Bigger = u128; - - #[derive(Clone)] - struct Test(Bigger); - impl Iterator for &mut Test { - type Item = i32; - fn next(&mut self) -> Option { - Some(21) - } - fn nth(&mut self, n: usize) -> Option { - self.0 += n as Bigger + 1; - Some(42) - } - } - - let mut it = Test(0); - let root = usize::MAX >> (usize::BITS / 2); - let n = root + 20; - (&mut it).step_by(n).nth(n); - assert_eq!(it.0, n as Bigger * n as Bigger); - - // large step - let mut it = Test(0); - (&mut it).step_by(usize::MAX).nth(5); - assert_eq!(it.0, (usize::MAX as Bigger) * 5); - - // n + 1 overflows - let mut it = Test(0); - (&mut it).step_by(2).nth(usize::MAX); - assert_eq!(it.0, (usize::MAX as Bigger) * 2); - - // n + 1 overflows - let mut it = Test(0); - (&mut it).step_by(1).nth(usize::MAX); - assert_eq!(it.0, (usize::MAX as Bigger) * 1); -} - -#[test] -fn test_iterator_step_by_nth_try_fold() { - let mut it = (0..).step_by(10); - assert_eq!(it.try_fold(0, i8::checked_add), None); - assert_eq!(it.next(), Some(60)); - assert_eq!(it.try_fold(0, i8::checked_add), None); - assert_eq!(it.next(), Some(90)); - - let mut it = (100..).step_by(10); - assert_eq!(it.try_fold(50, i8::checked_add), None); - assert_eq!(it.next(), Some(110)); - - let mut it = (100..=100).step_by(10); - assert_eq!(it.next(), Some(100)); - assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); -} - -#[test] -fn test_iterator_step_by_nth_back() { - let mut it = (0..16).step_by(5); - assert_eq!(it.nth_back(0), Some(15)); - assert_eq!(it.nth_back(0), Some(10)); - assert_eq!(it.nth_back(0), Some(5)); - assert_eq!(it.nth_back(0), Some(0)); - assert_eq!(it.nth_back(0), None); - - let mut it = (0..16).step_by(5); - assert_eq!(it.next(), Some(0)); // to set `first_take` to `false` - assert_eq!(it.nth_back(0), Some(15)); - assert_eq!(it.nth_back(0), Some(10)); - assert_eq!(it.nth_back(0), Some(5)); - assert_eq!(it.nth_back(0), None); - - let it = || (0..18).step_by(5); - assert_eq!(it().nth_back(0), Some(15)); - assert_eq!(it().nth_back(1), Some(10)); - assert_eq!(it().nth_back(2), Some(5)); - assert_eq!(it().nth_back(3), Some(0)); - assert_eq!(it().nth_back(4), None); - assert_eq!(it().nth_back(42), None); -} - -#[test] -fn test_iterator_step_by_nth_try_rfold() { - let mut it = (0..100).step_by(10); - assert_eq!(it.try_rfold(0, i8::checked_add), None); - assert_eq!(it.next_back(), Some(70)); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.try_rfold(0, i8::checked_add), None); - assert_eq!(it.next_back(), Some(30)); - - let mut it = (0..100).step_by(10); - assert_eq!(it.try_rfold(50, i8::checked_add), None); - assert_eq!(it.next_back(), Some(80)); - - let mut it = (100..=100).step_by(10); - assert_eq!(it.next_back(), Some(100)); - assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); -} - -#[test] -#[should_panic] -fn test_iterator_step_by_zero() { - let mut it = (0..).step_by(0); - it.next(); -} - -#[test] -fn test_iterator_step_by_size_hint() { - struct StubSizeHint(usize, Option); - impl Iterator for StubSizeHint { - type Item = (); - fn next(&mut self) -> Option<()> { - self.0 -= 1; - if let Some(ref mut upper) = self.1 { - *upper -= 1; - } - Some(()) - } - fn size_hint(&self) -> (usize, Option) { - (self.0, self.1) - } - } - - // The two checks in each case are needed because the logic - // is different before the first call to `next()`. - - let mut it = StubSizeHint(10, Some(10)).step_by(1); - assert_eq!(it.size_hint(), (10, Some(10))); - it.next(); - assert_eq!(it.size_hint(), (9, Some(9))); - - // exact multiple - let mut it = StubSizeHint(10, Some(10)).step_by(3); - assert_eq!(it.size_hint(), (4, Some(4))); - it.next(); - assert_eq!(it.size_hint(), (3, Some(3))); - - // larger base range, but not enough to get another element - let mut it = StubSizeHint(12, Some(12)).step_by(3); - assert_eq!(it.size_hint(), (4, Some(4))); - it.next(); - assert_eq!(it.size_hint(), (3, Some(3))); - - // smaller base range, so fewer resulting elements - let mut it = StubSizeHint(9, Some(9)).step_by(3); - assert_eq!(it.size_hint(), (3, Some(3))); - it.next(); - assert_eq!(it.size_hint(), (2, Some(2))); - - // infinite upper bound - let mut it = StubSizeHint(usize::MAX, None).step_by(1); - assert_eq!(it.size_hint(), (usize::MAX, None)); - it.next(); - assert_eq!(it.size_hint(), (usize::MAX - 1, None)); - - // still infinite with larger step - let mut it = StubSizeHint(7, None).step_by(3); - assert_eq!(it.size_hint(), (3, None)); - it.next(); - assert_eq!(it.size_hint(), (2, None)); - - // propagates ExactSizeIterator - let a = [1, 2, 3, 4, 5]; - let it = a.iter().step_by(2); - assert_eq!(it.len(), 3); - - // Cannot be TrustedLen as a step greater than one makes an iterator - // with (usize::MAX, None) no longer meet the safety requirements. - // Exception: The inner iterator is known to have a len() <= usize::MAX - trait TrustedLenCheck { - fn test(self) -> bool; - } - impl TrustedLenCheck for T { - default fn test(self) -> bool { - false - } - } - impl TrustedLenCheck for T { - fn test(self) -> bool { - true - } - } - assert!(TrustedLenCheck::test(a.iter())); - assert!(TrustedLenCheck::test(a.iter().step_by(1))); - assert!(TrustedLenCheck::test(a.iter().chain(a.iter()))); - assert!(!TrustedLenCheck::test(a.iter().chain(a.iter()).step_by(1))); -} - -#[test] -fn test_step_by_skip() { - assert_eq!((0..640).step_by(128).skip(1).collect::>(), [128, 256, 384, 512]); - assert_eq!((0..=50).step_by(10).nth(3), Some(30)); - assert_eq!((200..=255u8).step_by(10).nth(3), Some(230)); -} - -struct DeOpt(I); - -impl Iterator for DeOpt { - type Item = I::Item; - - fn next(&mut self) -> core::option::Option { - self.0.next() - } -} - -impl DoubleEndedIterator for DeOpt { - fn next_back(&mut self) -> core::option::Option { - self.0.next_back() - } -} - -#[test] -fn test_step_by_fold_range_specialization() { - macro_rules! t { - ($range:expr, $var: ident, $body:tt) => {{ - // run the same tests for the non-optimized version - let mut $var = DeOpt($range); - $body - } - { - let mut $var = $range; - $body - }}; - } - - t!((1usize..5).step_by(1), r, { - assert_eq!(r.next_back(), Some(4)); - assert_eq!(r.sum::(), 6); - }); - - t!((0usize..4).step_by(2), r, { - assert_eq!(r.next(), Some(0)); - assert_eq!(r.sum::(), 2); - }); - - t!((0usize..5).step_by(2), r, { - assert_eq!(r.next(), Some(0)); - assert_eq!(r.sum::(), 6); - }); - - t!((usize::MAX - 6..usize::MAX).step_by(5), r, { - assert_eq!(r.next(), Some(usize::MAX - 6)); - assert_eq!(r.sum::(), usize::MAX - 1); - }); -} diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs deleted file mode 100644 index b932059afec..00000000000 --- a/library/core/tests/iter/adapters/take.rs +++ /dev/null @@ -1,262 +0,0 @@ -use core::iter::*; -use core::num::NonZero; - -#[test] -fn test_iterator_take() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [0, 1, 2, 3, 5]; - - let mut it = xs.iter().take(ys.len()); - let mut i = 0; - assert_eq!(it.len(), ys.len()); - while let Some(&x) = it.next() { - assert_eq!(x, ys[i]); - i += 1; - assert_eq!(it.len(), ys.len() - i); - } - assert_eq!(i, ys.len()); - assert_eq!(it.len(), 0); - - let mut it = xs.iter().take(ys.len()); - let mut i = 0; - assert_eq!(it.len(), ys.len()); - while let Some(&x) = it.next_back() { - i += 1; - assert_eq!(x, ys[ys.len() - i]); - assert_eq!(it.len(), ys.len() - i); - } - assert_eq!(i, ys.len()); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_iterator_take_nth() { - let xs = [0, 1, 2, 4, 5]; - let mut it = xs.iter(); - { - let mut take = it.by_ref().take(3); - let mut i = 0; - while let Some(&x) = take.nth(0) { - assert_eq!(x, i); - i += 1; - } - } - assert_eq!(it.nth(1), Some(&5)); - assert_eq!(it.nth(0), None); - - let xs = [0, 1, 2, 3, 4]; - let mut it = xs.iter().take(7); - let mut i = 1; - while let Some(&x) = it.nth(1) { - assert_eq!(x, i); - i += 2; - } -} - -#[test] -fn test_iterator_take_nth_back() { - let xs = [0, 1, 2, 4, 5]; - let mut it = xs.iter(); - { - let mut take = it.by_ref().take(3); - let mut i = 0; - while let Some(&x) = take.nth_back(0) { - i += 1; - assert_eq!(x, 3 - i); - } - } - assert_eq!(it.nth_back(0), None); - - let xs = [0, 1, 2, 3, 4]; - let mut it = xs.iter().take(7); - assert_eq!(it.nth_back(1), Some(&3)); - assert_eq!(it.nth_back(1), Some(&1)); - assert_eq!(it.nth_back(1), None); -} - -#[test] -fn test_take_advance_by() { - let mut take = (0..10).take(3); - assert_eq!(take.advance_by(2), Ok(())); - assert_eq!(take.next(), Some(2)); - assert_eq!(take.advance_by(1), Err(NonZero::new(1).unwrap())); - - assert_eq!((0..0).take(10).advance_by(0), Ok(())); - assert_eq!((0..0).take(10).advance_by(1), Err(NonZero::new(1).unwrap())); - assert_eq!((0..10).take(4).advance_by(5), Err(NonZero::new(1).unwrap())); - - let mut take = (0..10).take(3); - assert_eq!(take.advance_back_by(2), Ok(())); - assert_eq!(take.next(), Some(0)); - assert_eq!(take.advance_back_by(1), Err(NonZero::new(1).unwrap())); - - assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZero::new(9).unwrap())); - assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZero::new(1).unwrap())); - assert_eq!((0..0).take(1).advance_back_by(0), Ok(())); - assert_eq!( - (0..usize::MAX).take(100).advance_back_by(usize::MAX), - Err(NonZero::new(usize::MAX - 100).unwrap()) - ); -} - -#[test] -fn test_iterator_take_short() { - let xs = [0, 1, 2, 3]; - - let mut it = xs.iter().take(5); - let mut i = 0; - assert_eq!(it.len(), xs.len()); - while let Some(&x) = it.next() { - assert_eq!(x, xs[i]); - i += 1; - assert_eq!(it.len(), xs.len() - i); - } - assert_eq!(i, xs.len()); - assert_eq!(it.len(), 0); - - let mut it = xs.iter().take(5); - let mut i = 0; - assert_eq!(it.len(), xs.len()); - while let Some(&x) = it.next_back() { - i += 1; - assert_eq!(x, xs[xs.len() - i]); - assert_eq!(it.len(), xs.len() - i); - } - assert_eq!(i, xs.len()); - assert_eq!(it.len(), 0); -} - -#[test] -fn test_take_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((10..30).take(10).try_fold(7, f), (10..20).try_fold(7, f)); - assert_eq!((10..30).take(10).try_rfold(7, f), (10..20).try_rfold(7, f)); - - let mut iter = (10..30).take(20); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(20)); - assert_eq!(iter.try_rfold(0, i8::checked_add), None); - assert_eq!(iter.next_back(), Some(24)); - - let mut iter = (2..20).take(3); - assert_eq!(iter.try_for_each(Err), Err(2)); - assert_eq!(iter.try_for_each(Err), Err(3)); - assert_eq!(iter.try_for_each(Err), Err(4)); - assert_eq!(iter.try_for_each(Err), Ok(())); - - let mut iter = (2..20).take(3).rev(); - assert_eq!(iter.try_for_each(Err), Err(4)); - assert_eq!(iter.try_for_each(Err), Err(3)); - assert_eq!(iter.try_for_each(Err), Err(2)); - assert_eq!(iter.try_for_each(Err), Ok(())); -} - -#[test] -fn test_byref_take_consumed_items() { - let mut inner = 10..90; - - let mut count = 0; - inner.by_ref().take(0).for_each(|_| count += 1); - assert_eq!(count, 0); - assert_eq!(inner, 10..90); - - let mut count = 0; - inner.by_ref().take(10).for_each(|_| count += 1); - assert_eq!(count, 10); - assert_eq!(inner, 20..90); - - let mut count = 0; - inner.by_ref().take(100).for_each(|_| count += 1); - assert_eq!(count, 70); - assert_eq!(inner, 90..90); -} - -#[test] -fn test_exact_size_take_repeat() { - let mut iter = core::iter::repeat(42).take(40); - assert_eq!((40, Some(40)), iter.size_hint()); - assert_eq!(40, iter.len()); - - assert_eq!(Some(42), iter.next()); - assert_eq!((39, Some(39)), iter.size_hint()); - assert_eq!(39, iter.len()); - - assert_eq!(Some(42), iter.next_back()); - assert_eq!((38, Some(38)), iter.size_hint()); - assert_eq!(38, iter.len()); - - assert_eq!(Some(42), iter.nth(3)); - assert_eq!((34, Some(34)), iter.size_hint()); - assert_eq!(34, iter.len()); - - assert_eq!(Some(42), iter.nth_back(3)); - assert_eq!((30, Some(30)), iter.size_hint()); - assert_eq!(30, iter.len()); - - assert_eq!(Ok(()), iter.advance_by(10)); - assert_eq!((20, Some(20)), iter.size_hint()); - assert_eq!(20, iter.len()); - - assert_eq!(Ok(()), iter.advance_back_by(10)); - assert_eq!((10, Some(10)), iter.size_hint()); - assert_eq!(10, iter.len()); -} - -#[test] -fn test_exact_size_take_repeat_with() { - let mut counter = 0; - let mut iter = core::iter::repeat_with(move || { - counter += 1; - counter - }) - .take(40); - assert_eq!((40, Some(40)), iter.size_hint()); - assert_eq!(40, iter.len()); - - assert_eq!(Some(1), iter.next()); - assert_eq!((39, Some(39)), iter.size_hint()); - assert_eq!(39, iter.len()); - - assert_eq!(Some(5), iter.nth(3)); - assert_eq!((35, Some(35)), iter.size_hint()); - assert_eq!(35, iter.len()); - - assert_eq!(Ok(()), iter.advance_by(10)); - assert_eq!((25, Some(25)), iter.size_hint()); - assert_eq!(25, iter.len()); - - assert_eq!(Some(16), iter.next()); - assert_eq!((24, Some(24)), iter.size_hint()); - assert_eq!(24, iter.len()); -} - -// This is https://github.com/rust-lang/rust/issues/104729 with all uses of -// repeat(0) were replaced by repeat(0).take(20). -#[test] -fn test_reverse_on_zip() { - let vec_1 = [1; 10]; - - let zipped_iter = vec_1.iter().copied().zip(core::iter::repeat(0).take(20)); - - // Forward - for (one, zero) in zipped_iter { - assert_eq!((1, 0), (one, zero)); - } - - let rev_vec_iter = vec_1.iter().rev(); - let rev_repeat_iter = std::iter::repeat(0).take(20).rev(); - - // Manual reversed zip - let rev_zipped_iter = rev_vec_iter.zip(rev_repeat_iter); - - for (&one, zero) in rev_zipped_iter { - assert_eq!((1, 0), (one, zero)); - } - - let zipped_iter = vec_1.iter().zip(core::iter::repeat(0).take(20)); - - // Cannot call rev here for automatic reversed zip construction - for (&one, zero) in zipped_iter.rev() { - assert_eq!((1, 0), (one, zero)); - } -} diff --git a/library/core/tests/iter/adapters/take_while.rs b/library/core/tests/iter/adapters/take_while.rs deleted file mode 100644 index 6f1ebab29b3..00000000000 --- a/library/core/tests/iter/adapters/take_while.rs +++ /dev/null @@ -1,29 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_take_while() { - let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - let ys = [0, 1, 2, 3, 5, 13]; - let it = xs.iter().take_while(|&x| *x < 15); - let mut i = 0; - for x in it { - assert_eq!(*x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); -} - -#[test] -fn test_take_while_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((1..20).take_while(|&x| x != 10).try_fold(7, f), (1..10).try_fold(7, f)); - let mut iter = (1..20).take_while(|&x| x != 10); - assert_eq!(iter.try_fold(0, |x, y| Some(x + y)), Some((1..10).sum())); - assert_eq!(iter.next(), None, "flag should be set"); - let iter = (1..20).take_while(|&x| x != 10); - assert_eq!(iter.fold(0, |x, y| x + y), (1..10).sum()); - - let mut iter = (10..50).take_while(|&x| x != 40); - assert_eq!(iter.try_fold(0, i8::checked_add), None); - assert_eq!(iter.next(), Some(20)); -} diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs deleted file mode 100644 index 70392dca0fa..00000000000 --- a/library/core/tests/iter/adapters/zip.rs +++ /dev/null @@ -1,319 +0,0 @@ -use core::iter::*; - -use super::*; - -#[test] -fn test_zip_nth() { - let xs = [0, 1, 2, 4, 5]; - let ys = [10, 11, 12]; - - let mut it = xs.iter().zip(&ys); - assert_eq!(it.nth(0), Some((&0, &10))); - assert_eq!(it.nth(1), Some((&2, &12))); - assert_eq!(it.nth(0), None); - - let mut it = xs.iter().zip(&ys); - assert_eq!(it.nth(3), None); - - let mut it = ys.iter().zip(&xs); - assert_eq!(it.nth(3), None); -} - -#[test] -fn test_zip_nth_side_effects() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let value = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })) - .skip(1) - .nth(3); - assert_eq!(value, Some((50, 6000))); - assert_eq!(a, vec![1, 2, 3, 4, 5]); - assert_eq!(b, vec![200, 300, 400, 500, 600]); -} - -#[test] -fn test_zip_next_back_side_effects() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let mut iter = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })); - - // The second iterator is one item longer, so `next_back` is called on it - // one more time. - assert_eq!(iter.next_back(), Some((60, 7000))); - assert_eq!(iter.next_back(), Some((50, 6000))); - assert_eq!(iter.next_back(), Some((40, 5000))); - assert_eq!(iter.next_back(), Some((30, 4000))); - assert_eq!(a, vec![6, 5, 4, 3]); - assert_eq!(b, vec![800, 700, 600, 500, 400]); -} - -#[test] -fn test_zip_nth_back_side_effects() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let value = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })) - .nth_back(3); - assert_eq!(value, Some((30, 4000))); - assert_eq!(a, vec![6, 5, 4, 3]); - assert_eq!(b, vec![800, 700, 600, 500, 400]); -} - -#[test] -fn test_zip_next_back_side_effects_exhausted() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let mut iter = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })); - - iter.next(); - iter.next(); - iter.next(); - iter.next(); - assert_eq!(iter.next_back(), None); - assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); - assert_eq!(b, vec![200, 300, 400]); -} - -#[test] -fn test_zip_cloned_sideffectful() { - let xs = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()]; - let ys = [CountClone::new(), CountClone::new()]; - - for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} - - assert_eq!(&xs, &[1, 1, 1, 0][..]); - assert_eq!(&ys, &[1, 1][..]); - - let xs = [CountClone::new(), CountClone::new()]; - let ys = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()]; - - for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} - - assert_eq!(&xs, &[1, 1][..]); - assert_eq!(&ys, &[1, 1, 0, 0][..]); -} - -#[test] -fn test_zip_map_sideffectful() { - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} - - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); - assert_eq!(&ys, &[1, 1, 1, 1]); - - let mut xs = [0; 4]; - let mut ys = [0; 6]; - - for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} - - assert_eq!(&xs, &[1, 1, 1, 1]); - assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); -} - -#[test] -fn test_zip_map_rev_sideffectful() { - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - { - let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - it.next_back(); - } - assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); - assert_eq!(&ys, &[0, 0, 0, 1]); - - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - { - let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - (&mut it).take(5).count(); - it.next_back(); - } - assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); - assert_eq!(&ys, &[1, 1, 1, 1]); -} - -#[test] -fn test_zip_nested_sideffectful() { - let mut xs = [0; 6]; - let ys = [0; 4]; - - { - // test that it has the side effect nested inside enumerate - let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); - it.count(); - } - let length_aware = &xs == &[1, 1, 1, 1, 0, 0]; - let probe_first = &xs == &[1, 1, 1, 1, 1, 0]; - - // either implementation is valid according to zip documentation - assert!(length_aware || probe_first); -} - -#[test] -fn test_zip_nth_back_side_effects_exhausted() { - let mut a = Vec::new(); - let mut b = Vec::new(); - let mut iter = [1, 2, 3, 4, 5, 6] - .iter() - .cloned() - .map(|n| { - a.push(n); - n * 10 - }) - .zip([2, 3, 4].iter().cloned().map(|n| { - b.push(n * 100); - n * 1000 - })); - - iter.next(); - iter.next(); - iter.next(); - iter.next(); - assert_eq!(iter.nth_back(0), None); - assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); - assert_eq!(b, vec![200, 300, 400]); -} - -#[test] -fn test_zip_trusted_random_access_composition() { - let a = [0, 1, 2, 3, 4]; - let b = a; - let c = a; - - let a = a.iter().copied(); - let b = b.iter().copied(); - let mut c = c.iter().copied(); - c.next(); - - let mut z1 = a.zip(b); - assert_eq!(z1.next().unwrap(), (0, 0)); - - let mut z2 = z1.zip(c); - fn assert_trusted_random_access(_a: &T) {} - assert_trusted_random_access(&z2); - assert_eq!(z2.next().unwrap(), ((1, 1), 1)); -} - -#[test] -#[cfg(panic = "unwind")] -fn test_zip_trusted_random_access_next_back_drop() { - use std::panic::{AssertUnwindSafe, catch_unwind}; - - let mut counter = 0; - - let it = [42].iter().map(|e| { - let c = counter; - counter += 1; - if c == 0 { - panic!("bomb"); - } - - e - }); - let it2 = [(); 0].iter(); - let mut zip = it.zip(it2); - catch_unwind(AssertUnwindSafe(|| { - zip.next_back(); - })) - .unwrap_err(); - assert!(zip.next().is_none()); - assert_eq!(counter, 1); -} - -#[test] -fn test_double_ended_zip() { - let xs = [1, 2, 3, 4, 5, 6]; - let ys = [1, 2, 3, 7]; - let mut it = xs.iter().cloned().zip(ys); - assert_eq!(it.next(), Some((1, 1))); - assert_eq!(it.next(), Some((2, 2))); - assert_eq!(it.next_back(), Some((4, 7))); - assert_eq!(it.next_back(), Some((3, 3))); - assert_eq!(it.next(), None); -} - -#[test] -fn test_issue_82282() { - fn overflowed_zip(arr: &[i32]) -> impl Iterator { - static UNIT_EMPTY_ARR: [(); 0] = []; - - let mapped = arr.into_iter().map(|i| *i); - let mut zipped = mapped.zip(UNIT_EMPTY_ARR.iter()); - zipped.next(); - zipped - } - - let arr = [1, 2, 3]; - let zip = overflowed_zip(&arr).zip(overflowed_zip(&arr)); - - assert_eq!(zip.size_hint(), (0, Some(0))); - for _ in zip { - panic!(); - } -} - -#[test] -fn test_issue_82291() { - use std::cell::Cell; - - let mut v1 = [()]; - let v2 = [()]; - - let called = Cell::new(0); - - let mut zip = v1 - .iter_mut() - .map(|r| { - called.set(called.get() + 1); - r - }) - .zip(&v2); - - zip.next_back(); - assert_eq!(called.get(), 1); - zip.next(); - assert_eq!(called.get(), 1); -} diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs deleted file mode 100644 index 5b2769d0469..00000000000 --- a/library/core/tests/iter/mod.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Note -//! ---- -//! You're probably viewing this file because you're adding a test (or you might -//! just be browsing, in that case, hey there!). -//! -//! The iter test suite is split into two big modules, and some miscellaneous -//! smaller modules. The two big modules are `adapters` and `traits`. -//! -//! `adapters` are for methods on `Iterator` that adapt the data inside the -//! iterator, whether it be by emitting another iterator or returning an item -//! from inside the iterator after executing a closure on each item. -//! -//! `traits` are for trait's that extend an `Iterator` (and the `Iterator` -//! trait itself, mostly containing miscellaneous methods). For the most part, -//! if a test in `traits` uses a specific adapter, then it should be moved to -//! that adapter's test file in `adapters`. - -mod adapters; -mod range; -mod sources; -mod traits; - -use core::cell::Cell; -use core::iter::*; - -pub fn is_trusted_len(_: I) {} - -#[test] -fn test_multi_iter() { - let xs = [1, 2, 3, 4]; - let ys = [4, 3, 2, 1]; - assert!(xs.iter().eq(ys.iter().rev())); - assert!(xs.iter().lt(xs.iter().skip(2))); -} - -#[test] -fn test_counter_from_iter() { - let it = (0..).step_by(5).take(10); - let xs: Vec = FromIterator::from_iter(it); - assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); -} - -#[test] -fn test_functor_laws() { - // identity: - fn identity(x: T) -> T { - x - } - assert_eq!((0..10).map(identity).sum::(), (0..10).sum()); - - // composition: - fn f(x: usize) -> usize { - x + 3 - } - fn g(x: usize) -> usize { - x * 2 - } - fn h(x: usize) -> usize { - g(f(x)) - } - assert_eq!((0..10).map(f).map(g).sum::(), (0..10).map(h).sum()); -} - -#[test] -fn test_monad_laws_left_identity() { - fn f(x: usize) -> impl Iterator { - (0..10).map(move |y| x * y) - } - assert_eq!(once(42).flat_map(f.clone()).sum::(), f(42).sum()); -} - -#[test] -fn test_monad_laws_right_identity() { - assert_eq!((0..10).flat_map(|x| once(x)).sum::(), (0..10).sum()); -} - -#[test] -fn test_monad_laws_associativity() { - fn f(x: usize) -> impl Iterator { - 0..x - } - fn g(x: usize) -> impl Iterator { - (0..x).rev() - } - assert_eq!( - (0..10).flat_map(f).flat_map(g).sum::(), - (0..10).flat_map(|x| f(x).flat_map(g)).sum::() - ); -} - -#[test] -pub fn extend_for_unit() { - let mut x = 0; - { - let iter = (0..5).map(|_| { - x += 1; - }); - ().extend(iter); - } - assert_eq!(x, 5); -} diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs deleted file mode 100644 index d5d2b8bf2b0..00000000000 --- a/library/core/tests/iter/range.rs +++ /dev/null @@ -1,504 +0,0 @@ -use core::ascii::Char as AsciiChar; -use core::num::NonZero; - -use super::*; - -#[test] -fn test_range() { - assert_eq!((0..5).collect::>(), [0, 1, 2, 3, 4]); - assert_eq!((-10..-1).collect::>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]); - assert_eq!((0..5).rev().collect::>(), [4, 3, 2, 1, 0]); - assert_eq!((200..-5).count(), 0); - assert_eq!((200..-5).rev().count(), 0); - assert_eq!((200..200).count(), 0); - assert_eq!((200..200).rev().count(), 0); - - assert_eq!((0..100).size_hint(), (100, Some(100))); - // this test is only meaningful when sizeof usize < sizeof u64 - assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1))); - assert_eq!((-10..-1).size_hint(), (9, Some(9))); - assert_eq!((-1..-10).size_hint(), (0, Some(0))); - - assert_eq!((-70..58).size_hint(), (128, Some(128))); - assert_eq!((-128..127).size_hint(), (255, Some(255))); - assert_eq!( - (-2..isize::MAX).size_hint(), - (isize::MAX as usize + 2, Some(isize::MAX as usize + 2)) - ); -} - -#[test] -fn test_char_range() { - // Miri is too slow - let from = if cfg!(miri) { char::from_u32(0xD800 - 10).unwrap() } else { '\0' }; - let to = if cfg!(miri) { char::from_u32(0xDFFF + 10).unwrap() } else { char::MAX }; - assert!((from..=to).eq((from as u32..=to as u32).filter_map(char::from_u32))); - assert!((from..=to).rev().eq((from as u32..=to as u32).filter_map(char::from_u32).rev())); - - assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2); - assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2))); - assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1); - assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1))); -} - -#[test] -fn test_ascii_char_range() { - let from = AsciiChar::Null; - let to = AsciiChar::Delete; - assert!((from..=to).eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8))); - assert!((from..=to).rev().eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8).rev())); - - assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).count(), 26); - assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).size_hint(), (26, Some(26))); - assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).count(), 26); - assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).size_hint(), (26, Some(26))); - assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).count(), 10); - assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).size_hint(), (10, Some(10))); -} - -#[test] -fn test_range_exhaustion() { - let mut r = 10..10; - assert!(r.is_empty()); - assert_eq!(r.next(), None); - assert_eq!(r.next_back(), None); - assert_eq!(r, 10..10); - - let mut r = 10..12; - assert_eq!(r.next(), Some(10)); - assert_eq!(r.next(), Some(11)); - assert!(r.is_empty()); - assert_eq!(r, 12..12); - assert_eq!(r.next(), None); - - let mut r = 10..12; - assert_eq!(r.next_back(), Some(11)); - assert_eq!(r.next_back(), Some(10)); - assert!(r.is_empty()); - assert_eq!(r, 10..10); - assert_eq!(r.next_back(), None); - - let mut r = 100..10; - assert!(r.is_empty()); - assert_eq!(r.next(), None); - assert_eq!(r.next_back(), None); - assert_eq!(r, 100..10); -} - -#[test] -fn test_range_inclusive_exhaustion() { - let mut r = 10..=10; - assert_eq!(r.next(), Some(10)); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - assert_eq!(r.next(), None); - - assert_eq!(*r.start(), 10); - assert_eq!(*r.end(), 10); - assert_ne!(r, 10..=10); - - let mut r = 10..=10; - assert_eq!(r.next_back(), Some(10)); - assert!(r.is_empty()); - assert_eq!(r.next_back(), None); - - assert_eq!(*r.start(), 10); - assert_eq!(*r.end(), 10); - assert_ne!(r, 10..=10); - - let mut r = 10..=12; - assert_eq!(r.next(), Some(10)); - assert_eq!(r.next(), Some(11)); - assert_eq!(r.next(), Some(12)); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - - let mut r = 10..=12; - assert_eq!(r.next_back(), Some(12)); - assert_eq!(r.next_back(), Some(11)); - assert_eq!(r.next_back(), Some(10)); - assert!(r.is_empty()); - assert_eq!(r.next_back(), None); - - let mut r = 10..=12; - assert_eq!(r.nth(2), Some(12)); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - - let mut r = 10..=12; - assert_eq!(r.nth(5), None); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - - let mut r = 100..=10; - assert_eq!(r.next(), None); - assert!(r.is_empty()); - assert_eq!(r.next(), None); - assert_eq!(r.next(), None); - assert_eq!(r, 100..=10); - - let mut r = 100..=10; - assert_eq!(r.next_back(), None); - assert!(r.is_empty()); - assert_eq!(r.next_back(), None); - assert_eq!(r.next_back(), None); - assert_eq!(r, 100..=10); -} - -#[test] -fn test_range_nth() { - assert_eq!((10..15).nth(0), Some(10)); - assert_eq!((10..15).nth(1), Some(11)); - assert_eq!((10..15).nth(4), Some(14)); - assert_eq!((10..15).nth(5), None); - - let mut r = 10..20; - assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 13..20); - assert_eq!(r.nth(2), Some(15)); - assert_eq!(r, 16..20); - assert_eq!(r.nth(10), None); - assert_eq!(r, 20..20); -} - -#[test] -fn test_range_nth_back() { - assert_eq!((10..15).nth_back(0), Some(14)); - assert_eq!((10..15).nth_back(1), Some(13)); - assert_eq!((10..15).nth_back(4), Some(10)); - assert_eq!((10..15).nth_back(5), None); - assert_eq!((-120..80_i8).nth_back(199), Some(-120)); - - let mut r = 10..20; - assert_eq!(r.nth_back(2), Some(17)); - assert_eq!(r, 10..17); - assert_eq!(r.nth_back(2), Some(14)); - assert_eq!(r, 10..14); - assert_eq!(r.nth_back(10), None); - assert_eq!(r, 10..10); -} - -#[test] -fn test_range_from_nth() { - assert_eq!((10..).nth(0), Some(10)); - assert_eq!((10..).nth(1), Some(11)); - assert_eq!((10..).nth(4), Some(14)); - - let mut r = 10..; - assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 13..); - assert_eq!(r.nth(2), Some(15)); - assert_eq!(r, 16..); - assert_eq!(r.nth(10), Some(26)); - assert_eq!(r, 27..); - - assert_eq!((0..).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_range_from_take() { - let mut it = (0..).take(3); - assert_eq!(it.next(), Some(0)); - assert_eq!(it.next(), Some(1)); - assert_eq!(it.next(), Some(2)); - assert_eq!(it.next(), None); - is_trusted_len((0..).take(3)); - assert_eq!((0..).take(3).size_hint(), (3, Some(3))); - assert_eq!((0..).take(0).size_hint(), (0, Some(0))); - assert_eq!((0..).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); -} - -#[test] -fn test_range_from_take_collect() { - let v: Vec<_> = (0..).take(3).collect(); - assert_eq!(v, vec![0, 1, 2]); -} - -#[test] -fn test_range_inclusive_nth() { - assert_eq!((10..=15).nth(0), Some(10)); - assert_eq!((10..=15).nth(1), Some(11)); - assert_eq!((10..=15).nth(5), Some(15)); - assert_eq!((10..=15).nth(6), None); - - let mut exhausted_via_next = 10_u8..=20; - while exhausted_via_next.next().is_some() {} - - let mut r = 10_u8..=20; - assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 13..=20); - assert_eq!(r.nth(2), Some(15)); - assert_eq!(r, 16..=20); - assert_eq!(r.is_empty(), false); - assert_eq!(ExactSizeIterator::is_empty(&r), false); - assert_eq!(r.nth(10), None); - assert_eq!(r.is_empty(), true); - assert_eq!(r, exhausted_via_next); - assert_eq!(ExactSizeIterator::is_empty(&r), true); -} - -#[test] -fn test_range_inclusive_nth_back() { - assert_eq!((10..=15).nth_back(0), Some(15)); - assert_eq!((10..=15).nth_back(1), Some(14)); - assert_eq!((10..=15).nth_back(5), Some(10)); - assert_eq!((10..=15).nth_back(6), None); - assert_eq!((-120..=80_i8).nth_back(200), Some(-120)); - - let mut exhausted_via_next_back = 10_u8..=20; - while exhausted_via_next_back.next_back().is_some() {} - - let mut r = 10_u8..=20; - assert_eq!(r.nth_back(2), Some(18)); - assert_eq!(r, 10..=17); - assert_eq!(r.nth_back(2), Some(15)); - assert_eq!(r, 10..=14); - assert_eq!(r.is_empty(), false); - assert_eq!(ExactSizeIterator::is_empty(&r), false); - assert_eq!(r.nth_back(10), None); - assert_eq!(r.is_empty(), true); - assert_eq!(r, exhausted_via_next_back); - assert_eq!(ExactSizeIterator::is_empty(&r), true); -} - -#[test] -fn test_range_len() { - assert_eq!((0..10_u8).len(), 10); - assert_eq!((9..10_u8).len(), 1); - assert_eq!((10..10_u8).len(), 0); - assert_eq!((11..10_u8).len(), 0); - assert_eq!((100..10_u8).len(), 0); -} - -#[test] -fn test_range_inclusive_len() { - assert_eq!((0..=10_u8).len(), 11); - assert_eq!((9..=10_u8).len(), 2); - assert_eq!((10..=10_u8).len(), 1); - assert_eq!((11..=10_u8).len(), 0); - assert_eq!((100..=10_u8).len(), 0); -} - -#[test] -fn test_range_step() { - #![allow(deprecated)] - - assert_eq!((0..20).step_by(5).collect::>(), [0, 5, 10, 15]); - assert_eq!((1..21).rev().step_by(5).collect::>(), [20, 15, 10, 5]); - assert_eq!((1..21).rev().step_by(6).collect::>(), [20, 14, 8, 2]); - assert_eq!((200..255).step_by(50).collect::>(), [200, 250]); - assert_eq!((200..-5).step_by(1).collect::>(), []); - assert_eq!((200..200).step_by(1).collect::>(), []); - - assert_eq!((0..20).step_by(1).size_hint(), (20, Some(20))); - assert_eq!((0..20).step_by(21).size_hint(), (1, Some(1))); - assert_eq!((0..20).step_by(5).size_hint(), (4, Some(4))); - assert_eq!((1..21).rev().step_by(5).size_hint(), (4, Some(4))); - assert_eq!((1..21).rev().step_by(6).size_hint(), (4, Some(4))); - assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0))); - assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0))); - assert_eq!((i8::MIN..i8::MAX).step_by(-(i8::MIN as i32) as usize).size_hint(), (2, Some(2))); - assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX as usize).size_hint(), (3, Some(3))); - assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); -} - -#[test] -fn test_range_advance_by() { - let mut r = 0..usize::MAX; - assert_eq!(Ok(()), r.advance_by(0)); - assert_eq!(Ok(()), r.advance_back_by(0)); - - assert_eq!(r.len(), usize::MAX); - - assert_eq!(Ok(()), r.advance_by(1)); - assert_eq!(Ok(()), r.advance_back_by(1)); - - assert_eq!((r.start, r.end), (1, usize::MAX - 1)); - - assert_eq!(Err(NonZero::new(2).unwrap()), r.advance_by(usize::MAX)); - - assert_eq!(Ok(()), r.advance_by(0)); - assert_eq!(Ok(()), r.advance_back_by(0)); - - let mut r = 0u128..u128::MAX; - - assert_eq!(Ok(()), r.advance_by(usize::MAX)); - assert_eq!(Ok(()), r.advance_back_by(usize::MAX)); - - assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128)); - - // issue 122420, Step::forward_unchecked was unsound for signed integers - let mut r = -128i8..127; - assert_eq!(Ok(()), r.advance_by(200)); - assert_eq!(r.next(), Some(72)); -} - -#[test] -fn test_range_inclusive_step() { - assert_eq!((0..=50).step_by(10).collect::>(), [0, 10, 20, 30, 40, 50]); - assert_eq!((0..=5).step_by(1).collect::>(), [0, 1, 2, 3, 4, 5]); - assert_eq!((200..=255u8).step_by(10).collect::>(), [200, 210, 220, 230, 240, 250]); - assert_eq!((250..=255u8).step_by(1).collect::>(), [250, 251, 252, 253, 254, 255]); -} - -#[test] -fn test_range_last_max() { - assert_eq!((0..20).last(), Some(19)); - assert_eq!((-20..0).last(), Some(-1)); - assert_eq!((5..5).last(), None); - - assert_eq!((0..20).max(), Some(19)); - assert_eq!((-20..0).max(), Some(-1)); - assert_eq!((5..5).max(), None); -} - -#[test] -fn test_range_inclusive_last_max() { - assert_eq!((0..=20).last(), Some(20)); - assert_eq!((-20..=0).last(), Some(0)); - assert_eq!((5..=5).last(), Some(5)); - let mut r = 10..=10; - r.next(); - assert_eq!(r.last(), None); - - assert_eq!((0..=20).max(), Some(20)); - assert_eq!((-20..=0).max(), Some(0)); - assert_eq!((5..=5).max(), Some(5)); - let mut r = 10..=10; - r.next(); - assert_eq!(r.max(), None); -} - -#[test] -fn test_range_min() { - assert_eq!((0..20).min(), Some(0)); - assert_eq!((-20..0).min(), Some(-20)); - assert_eq!((5..5).min(), None); -} - -#[test] -fn test_range_inclusive_min() { - assert_eq!((0..=20).min(), Some(0)); - assert_eq!((-20..=0).min(), Some(-20)); - assert_eq!((5..=5).min(), Some(5)); - let mut r = 10..=10; - r.next(); - assert_eq!(r.min(), None); -} - -#[test] -fn test_range_inclusive_folds() { - assert_eq!((1..=10).sum::(), 55); - assert_eq!((1..=10).rev().sum::(), 55); - - let mut it = 44..=50; - assert_eq!(it.try_fold(0, i8::checked_add), None); - assert_eq!(it, 47..=50); - assert_eq!(it.try_fold(0, i8::checked_add), None); - assert_eq!(it, 50..=50); - assert_eq!(it.try_fold(0, i8::checked_add), Some(50)); - assert!(it.is_empty()); - assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); - assert!(it.is_empty()); - - let mut it = 40..=47; - assert_eq!(it.try_rfold(0, i8::checked_add), None); - assert_eq!(it, 40..=44); - assert_eq!(it.try_rfold(0, i8::checked_add), None); - assert_eq!(it, 40..=41); - assert_eq!(it.try_rfold(0, i8::checked_add), Some(81)); - assert!(it.is_empty()); - assert_eq!(it.try_rfold(0, i8::checked_add), Some(0)); - assert!(it.is_empty()); - - let mut it = 10..=20; - assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(165)); - assert!(it.is_empty()); - assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(0)); - assert!(it.is_empty()); - - let mut it = 10..=20; - assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(165)); - assert!(it.is_empty()); - assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(0)); - assert!(it.is_empty()); -} - -#[test] -fn test_range_size_hint() { - assert_eq!((0..0usize).size_hint(), (0, Some(0))); - assert_eq!((0..100usize).size_hint(), (100, Some(100))); - assert_eq!((0..usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); - - let umax = u128::try_from(usize::MAX).unwrap(); - assert_eq!((0..0u128).size_hint(), (0, Some(0))); - assert_eq!((0..100u128).size_hint(), (100, Some(100))); - assert_eq!((0..umax).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((0..umax + 1).size_hint(), (usize::MAX, None)); - - assert_eq!((0..0isize).size_hint(), (0, Some(0))); - assert_eq!((-100..100isize).size_hint(), (200, Some(200))); - assert_eq!((isize::MIN..isize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); - - let imin = i128::try_from(isize::MIN).unwrap(); - let imax = i128::try_from(isize::MAX).unwrap(); - assert_eq!((0..0i128).size_hint(), (0, Some(0))); - assert_eq!((-100..100i128).size_hint(), (200, Some(200))); - assert_eq!((imin..imax).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((imin..imax + 1).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_range_inclusive_size_hint() { - assert_eq!((1..=0usize).size_hint(), (0, Some(0))); - assert_eq!((0..=0usize).size_hint(), (1, Some(1))); - assert_eq!((0..=100usize).size_hint(), (101, Some(101))); - assert_eq!((0..=usize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((0..=usize::MAX).size_hint(), (usize::MAX, None)); - - let umax = u128::try_from(usize::MAX).unwrap(); - assert_eq!((1..=0u128).size_hint(), (0, Some(0))); - assert_eq!((0..=0u128).size_hint(), (1, Some(1))); - assert_eq!((0..=100u128).size_hint(), (101, Some(101))); - assert_eq!((0..=umax - 1).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((0..=umax).size_hint(), (usize::MAX, None)); - assert_eq!((0..=umax + 1).size_hint(), (usize::MAX, None)); - - assert_eq!((0..=-1isize).size_hint(), (0, Some(0))); - assert_eq!((0..=0isize).size_hint(), (1, Some(1))); - assert_eq!((-100..=100isize).size_hint(), (201, Some(201))); - assert_eq!((isize::MIN..=isize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((isize::MIN..=isize::MAX).size_hint(), (usize::MAX, None)); - - let imin = i128::try_from(isize::MIN).unwrap(); - let imax = i128::try_from(isize::MAX).unwrap(); - assert_eq!((0..=-1i128).size_hint(), (0, Some(0))); - assert_eq!((0..=0i128).size_hint(), (1, Some(1))); - assert_eq!((-100..=100i128).size_hint(), (201, Some(201))); - assert_eq!((imin..=imax - 1).size_hint(), (usize::MAX, Some(usize::MAX))); - assert_eq!((imin..=imax).size_hint(), (usize::MAX, None)); - assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_range_trusted_random_access() { - let mut range = 0..10; - unsafe { - assert_eq!(range.next(), Some(0)); - assert_eq!(range.__iterator_get_unchecked(0), 1); - assert_eq!(range.__iterator_get_unchecked(1), 2); - } -} - -#[test] -fn test_double_ended_range() { - assert_eq!((11..14).rev().collect::>(), [13, 12, 11]); - for _ in (10..0).rev() { - panic!("unreachable"); - } - - assert_eq!((11..14).rev().collect::>(), [13, 12, 11]); - for _ in (10..0).rev() { - panic!("unreachable"); - } -} diff --git a/library/core/tests/iter/sources.rs b/library/core/tests/iter/sources.rs deleted file mode 100644 index 506febaa056..00000000000 --- a/library/core/tests/iter/sources.rs +++ /dev/null @@ -1,182 +0,0 @@ -use core::iter::*; - -use super::*; - -#[test] -fn test_repeat() { - let mut it = repeat(42); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(repeat(42).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_repeat_take() { - let mut it = repeat(42).take(3); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), None); - is_trusted_len(repeat(42).take(3)); - assert_eq!(repeat(42).take(3).size_hint(), (3, Some(3))); - assert_eq!(repeat(42).take(0).size_hint(), (0, Some(0))); - assert_eq!(repeat(42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); -} - -#[test] -fn test_repeat_take_collect() { - let v: Vec<_> = repeat(42).take(3).collect(); - assert_eq!(v, vec![42, 42, 42]); -} - -#[test] -fn test_repeat_with() { - #[derive(PartialEq, Debug)] - struct NotClone(usize); - let mut it = repeat_with(|| NotClone(42)); - assert_eq!(it.next(), Some(NotClone(42))); - assert_eq!(it.next(), Some(NotClone(42))); - assert_eq!(it.next(), Some(NotClone(42))); - assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); -} - -#[test] -fn test_repeat_with_take() { - let mut it = repeat_with(|| 42).take(3); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), None); - is_trusted_len(repeat_with(|| 42).take(3)); - assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3))); - assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0))); - assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); -} - -#[test] -fn test_repeat_with_take_collect() { - let mut curr = 1; - let v: Vec<_> = repeat_with(|| { - let tmp = curr; - curr *= 2; - tmp - }) - .take(5) - .collect(); - assert_eq!(v, vec![1, 2, 4, 8, 16]); -} - -#[test] -fn test_successors() { - let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); - assert_eq!(powers_of_10.by_ref().collect::>(), &[1, 10, 100, 1_000, 10_000]); - assert_eq!(powers_of_10.next(), None); - - let mut empty = successors(None::, |_| unimplemented!()); - assert_eq!(empty.next(), None); - assert_eq!(empty.next(), None); -} - -#[test] -fn test_once() { - let mut it = once(42); - assert_eq!(it.next(), Some(42)); - assert_eq!(it.next(), None); -} - -#[test] -fn test_once_with() { - let count = Cell::new(0); - let mut it = once_with(|| { - count.set(count.get() + 1); - 42 - }); - - assert_eq!(count.get(), 0); - assert_eq!(it.next(), Some(42)); - assert_eq!(count.get(), 1); - assert_eq!(it.next(), None); - assert_eq!(count.get(), 1); - assert_eq!(it.next(), None); - assert_eq!(count.get(), 1); -} - -#[test] -fn test_empty() { - let mut it = empty::(); - assert_eq!(it.next(), None); -} - -#[test] -fn test_repeat_n_drop() { - #[derive(Clone, Debug)] - struct DropCounter<'a>(&'a Cell); - impl Drop for DropCounter<'_> { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } - } - - // `repeat_n(x, 0)` drops `x` immediately - let count = Cell::new(0); - let item = DropCounter(&count); - let mut it = repeat_n(item, 0); - assert_eq!(count.get(), 1); - assert!(it.next().is_none()); - assert_eq!(count.get(), 1); - drop(it); - assert_eq!(count.get(), 1); - - // Dropping the iterator needs to drop the item if it's non-empty - let count = Cell::new(0); - let item = DropCounter(&count); - let it = repeat_n(item, 3); - assert_eq!(count.get(), 0); - drop(it); - assert_eq!(count.get(), 1); - - // Dropping the iterator doesn't drop the item if it was exhausted - let count = Cell::new(0); - let item = DropCounter(&count); - let mut it = repeat_n(item, 3); - assert_eq!(count.get(), 0); - let x0 = it.next().unwrap(); - assert_eq!(count.get(), 0); - let x1 = it.next().unwrap(); - assert_eq!(count.get(), 0); - let x2 = it.next().unwrap(); - assert_eq!(count.get(), 0); - assert!(it.next().is_none()); - assert_eq!(count.get(), 0); - assert!(it.next().is_none()); - assert_eq!(count.get(), 0); - drop(it); - assert_eq!(count.get(), 0); - drop((x0, x1, x2)); - assert_eq!(count.get(), 3); -} - -#[test] -fn test_repeat_n_soundness() { - let x = std::iter::repeat_n(String::from("use after free"), 0); - println!("{x:?}"); - - pub struct PanicOnClone; - - impl Clone for PanicOnClone { - fn clone(&self) -> Self { - unreachable!() - } - } - - // `repeat_n` should drop the element immediately if `count` is zero. - // `Clone` should then not try to clone the element. - let x = std::iter::repeat_n(PanicOnClone, 0); - let _ = x.clone(); - - let mut y = std::iter::repeat_n(Box::new(0), 1); - let x = y.next().unwrap(); - let _z = y; - assert_eq!(0, *x); -} diff --git a/library/core/tests/iter/traits/accum.rs b/library/core/tests/iter/traits/accum.rs deleted file mode 100644 index f3eeb31fe58..00000000000 --- a/library/core/tests/iter/traits/accum.rs +++ /dev/null @@ -1,66 +0,0 @@ -use core::iter::*; - -#[test] -fn test_iterator_sum() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().sum::(), 6); - assert_eq!(v.iter().cloned().sum::(), 55); - assert_eq!(v[..0].iter().cloned().sum::(), 0); -} - -#[test] -fn test_iterator_sum_result() { - let v: &[Result] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().sum::>(), Ok(10)); - let v: &[Result] = &[Ok(1), Err(()), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().sum::>(), Err(())); - - #[derive(PartialEq, Debug)] - struct S(Result); - - impl Sum> for S { - fn sum>>(mut iter: I) -> Self { - // takes the sum by repeatedly calling `next` on `iter`, - // thus testing that repeated calls to `ResultShunt::try_fold` - // produce the expected results - Self(iter.by_ref().sum()) - } - } - - let v: &[Result] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().sum::(), S(Ok(10))); - let v: &[Result] = &[Ok(1), Err(()), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().sum::(), S(Err(()))); -} - -#[test] -fn test_iterator_sum_option() { - let v: &[Option] = &[Some(1), Some(2), Some(3), Some(4)]; - assert_eq!(v.iter().cloned().sum::>(), Some(10)); - let v: &[Option] = &[Some(1), None, Some(3), Some(4)]; - assert_eq!(v.iter().cloned().sum::>(), None); -} - -#[test] -fn test_iterator_product() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().product::(), 0); - assert_eq!(v[1..5].iter().cloned().product::(), 24); - assert_eq!(v[..0].iter().cloned().product::(), 1); -} - -#[test] -fn test_iterator_product_result() { - let v: &[Result] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().product::>(), Ok(24)); - let v: &[Result] = &[Ok(1), Err(()), Ok(3), Ok(4)]; - assert_eq!(v.iter().cloned().product::>(), Err(())); -} - -#[test] -fn test_iterator_product_option() { - let v: &[Option] = &[Some(1), Some(2), Some(3), Some(4)]; - assert_eq!(v.iter().cloned().product::>(), Some(24)); - let v: &[Option] = &[Some(1), None, Some(3), Some(4)]; - assert_eq!(v.iter().cloned().product::>(), None); -} diff --git a/library/core/tests/iter/traits/double_ended.rs b/library/core/tests/iter/traits/double_ended.rs deleted file mode 100644 index 00ef4a6e6a9..00000000000 --- a/library/core/tests/iter/traits/double_ended.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! Note -//! ---- -//! You're probably viewing this file because you're adding a test (or you might -//! just be browsing, in that case, hey there!). -//! -//! If you've made a test that happens to use one of DoubleEnded's methods, but -//! it tests another adapter or trait, you should *add it to the adapter or -//! trait's test file*. -//! -//! Some examples would be `adapters::cloned::test_cloned_try_folds` or -//! `adapters::flat_map::test_double_ended_flat_map`, which use `try_fold` and -//! `next_back`, but test their own adapter. - -#[test] -fn test_iterator_rev_nth_back() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]); - } - assert_eq!(v.iter().rev().nth_back(v.len()), None); -} - -#[test] -fn test_iterator_rev_nth() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]); - } - assert_eq!(v.iter().rev().nth(v.len()), None); -} - -#[test] -fn test_rev() { - let xs = [2, 4, 6, 8, 10, 12, 14, 16]; - let mut it = xs.iter(); - it.next(); - it.next(); - assert!(it.rev().cloned().collect::>() == vec![16, 14, 12, 10, 8, 6]); -} - -#[test] -fn test_rev_try_folds() { - let f = &|acc, x| i32::checked_add(2 * acc, x); - assert_eq!((1..10).rev().try_fold(7, f), (1..10).try_rfold(7, f)); - assert_eq!((1..10).rev().try_rfold(7, f), (1..10).try_fold(7, f)); - - let a = [10, 20, 30, 40, 100, 60, 70, 80, 90]; - let mut iter = a.iter().rev(); - assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None); - assert_eq!(iter.next(), Some(&70)); - let mut iter = a.iter().rev(); - assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); - assert_eq!(iter.next_back(), Some(&60)); -} - -#[test] -fn test_rposition() { - fn f(xy: &(isize, char)) -> bool { - let (_x, y) = *xy; - y == 'b' - } - fn g(xy: &(isize, char)) -> bool { - let (_x, y) = *xy; - y == 'd' - } - let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert_eq!(v.iter().rposition(f), Some(3)); - assert!(v.iter().rposition(g).is_none()); -} - -#[test] -fn test_rev_rposition() { - let v = [0, 0, 1, 1]; - assert_eq!(v.iter().rev().rposition(|&x| x == 1), Some(1)); -} - -#[test] -#[should_panic] -fn test_rposition_panic() { - let u = (Box::new(0), Box::new(0)); - let v: [(Box<_>, Box<_>); 4] = [u.clone(), u.clone(), u.clone(), u]; - let mut i = 0; - v.iter().rposition(|_elt| { - if i == 2 { - panic!() - } - i += 1; - false - }); -} diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs deleted file mode 100644 index e31d2e15b6d..00000000000 --- a/library/core/tests/iter/traits/iterator.rs +++ /dev/null @@ -1,651 +0,0 @@ -use core::num::NonZero; - -/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped -/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min` -/// return the correct element if some of them are equal. -#[derive(Debug)] -struct Mod3(i32); - -impl PartialEq for Mod3 { - fn eq(&self, other: &Self) -> bool { - self.0 % 3 == other.0 % 3 - } -} - -impl Eq for Mod3 {} - -impl PartialOrd for Mod3 { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Mod3 { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - (self.0 % 3).cmp(&(other.0 % 3)) - } -} - -#[test] -fn test_lt() { - let empty: [isize; 0] = []; - let xs = [1, 2, 3]; - let ys = [1, 2, 0]; - - assert!(!xs.iter().lt(ys.iter())); - assert!(!xs.iter().le(ys.iter())); - assert!(xs.iter().gt(ys.iter())); - assert!(xs.iter().ge(ys.iter())); - - assert!(ys.iter().lt(xs.iter())); - assert!(ys.iter().le(xs.iter())); - assert!(!ys.iter().gt(xs.iter())); - assert!(!ys.iter().ge(xs.iter())); - - assert!(empty.iter().lt(xs.iter())); - assert!(empty.iter().le(xs.iter())); - assert!(!empty.iter().gt(xs.iter())); - assert!(!empty.iter().ge(xs.iter())); - - // Sequence with NaN - let u = [1.0f64, 2.0]; - let v = [0.0f64 / 0.0, 3.0]; - - assert!(!u.iter().lt(v.iter())); - assert!(!u.iter().le(v.iter())); - assert!(!u.iter().gt(v.iter())); - assert!(!u.iter().ge(v.iter())); - - let a = [0.0f64 / 0.0]; - let b = [1.0f64]; - let c = [2.0f64]; - - assert!(a.iter().lt(b.iter()) == (a[0] < b[0])); - assert!(a.iter().le(b.iter()) == (a[0] <= b[0])); - assert!(a.iter().gt(b.iter()) == (a[0] > b[0])); - assert!(a.iter().ge(b.iter()) == (a[0] >= b[0])); - - assert!(c.iter().lt(b.iter()) == (c[0] < b[0])); - assert!(c.iter().le(b.iter()) == (c[0] <= b[0])); - assert!(c.iter().gt(b.iter()) == (c[0] > b[0])); - assert!(c.iter().ge(b.iter()) == (c[0] >= b[0])); -} - -#[test] -fn test_cmp_by() { - use core::cmp::Ordering; - - let f = |x: i32, y: i32| (x * x).cmp(&y); - let xs = || [1, 2, 3, 4].iter().copied(); - let ys = || [1, 4, 16].iter().copied(); - - assert_eq!(xs().cmp_by(ys(), f), Ordering::Less); - assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater); - assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal); - assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater); - assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less); - assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater); -} - -#[test] -fn test_partial_cmp_by() { - use core::cmp::Ordering; - - let f = |x: i32, y: i32| (x * x).partial_cmp(&y); - let xs = || [1, 2, 3, 4].iter().copied(); - let ys = || [1, 4, 16].iter().copied(); - - assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less)); - assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); - assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal)); - assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater)); - assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less)); - assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater)); - - let f = |x: f64, y: f64| (x * x).partial_cmp(&y); - let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied(); - let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied(); - - assert_eq!(xs().partial_cmp_by(ys(), f), None); - assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); -} - -#[test] -fn test_eq_by() { - let f = |x: i32, y: i32| x * x == y; - let xs = || [1, 2, 3, 4].iter().copied(); - let ys = || [1, 4, 9, 16].iter().copied(); - - assert!(xs().eq_by(ys(), f)); - assert!(!ys().eq_by(xs(), f)); - assert!(!xs().eq_by(xs(), f)); - assert!(!ys().eq_by(ys(), f)); - - assert!(!xs().take(3).eq_by(ys(), f)); - assert!(!xs().eq_by(ys().take(3), f)); - assert!(xs().take(3).eq_by(ys().take(3), f)); -} - -#[test] -fn test_iterator_nth() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().nth(i).unwrap(), &v[i]); - } - assert_eq!(v.iter().nth(v.len()), None); -} - -#[test] -fn test_iterator_nth_back() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]); - } - assert_eq!(v.iter().nth_back(v.len()), None); -} - -#[test] -fn test_iterator_advance_by() { - let v: &[_] = &[0, 1, 2, 3, 4]; - - for i in 0..v.len() { - let mut iter = v.iter(); - assert_eq!(iter.advance_by(i), Ok(())); - assert_eq!(iter.next().unwrap(), &v[i]); - assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap())); - } - - assert_eq!(v.iter().advance_by(v.len()), Ok(())); - assert_eq!(v.iter().advance_by(100), Err(NonZero::new(100 - v.len()).unwrap())); -} - -#[test] -fn test_iterator_advance_back_by() { - let v: &[_] = &[0, 1, 2, 3, 4]; - - for i in 0..v.len() { - let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(i), Ok(())); - assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]); - assert_eq!(iter.advance_back_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap())); - } - - assert_eq!(v.iter().advance_back_by(v.len()), Ok(())); - assert_eq!(v.iter().advance_back_by(100), Err(NonZero::new(100 - v.len()).unwrap())); -} - -#[test] -fn test_iterator_rev_advance_back_by() { - let v: &[_] = &[0, 1, 2, 3, 4]; - - for i in 0..v.len() { - let mut iter = v.iter().rev(); - assert_eq!(iter.advance_back_by(i), Ok(())); - assert_eq!(iter.next_back().unwrap(), &v[i]); - assert_eq!(iter.advance_back_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap())); - } - - assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(())); - assert_eq!(v.iter().rev().advance_back_by(100), Err(NonZero::new(100 - v.len()).unwrap())); -} - -#[test] -fn test_iterator_last() { - let v: &[_] = &[0, 1, 2, 3, 4]; - assert_eq!(v.iter().last().unwrap(), &4); - assert_eq!(v[..1].iter().last().unwrap(), &0); -} - -#[test] -fn test_iterator_max() { - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().max(), Some(3)); - assert_eq!(v.iter().cloned().max(), Some(10)); - assert_eq!(v[..0].iter().cloned().max(), None); - assert_eq!(v.iter().cloned().map(Mod3).max().map(|x| x.0), Some(8)); -} - -#[test] -fn test_iterator_min() { - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().min(), Some(0)); - assert_eq!(v.iter().cloned().min(), Some(0)); - assert_eq!(v[..0].iter().cloned().min(), None); - assert_eq!(v.iter().cloned().map(Mod3).min().map(|x| x.0), Some(0)); -} - -#[test] -fn test_iterator_size_hint() { - let c = (0..).step_by(1); - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let v2 = &[10, 11, 12]; - let vi = v.iter(); - - assert_eq!((0..).size_hint(), (usize::MAX, None)); - assert_eq!(c.size_hint(), (usize::MAX, None)); - assert_eq!(vi.clone().size_hint(), (10, Some(10))); - - assert_eq!(c.clone().take(5).size_hint(), (5, Some(5))); - assert_eq!(c.clone().skip(5).size_hint().1, None); - assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None)); - assert_eq!(c.clone().map_while(|_| None::<()>).size_hint(), (0, None)); - assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None)); - assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None)); - assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None)); - assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10))); - assert_eq!(c.clone().scan(0, |_, _| Some(0)).size_hint(), (0, None)); - assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None)); - assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None)); - assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None)); - - assert_eq!(vi.clone().take(5).size_hint(), (5, Some(5))); - assert_eq!(vi.clone().take(12).size_hint(), (10, Some(10))); - assert_eq!(vi.clone().skip(3).size_hint(), (7, Some(7))); - assert_eq!(vi.clone().skip(12).size_hint(), (0, Some(0))); - assert_eq!(vi.clone().take_while(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().map_while(|_| None::<()>).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().skip_while(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10))); - assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13))); - assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3))); - assert_eq!(vi.clone().scan(0, |_, _| Some(0)).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.clone().map(|&i| i + 1).size_hint(), (10, Some(10))); - assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10))); -} - -#[test] -fn test_all() { - let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); - assert!(v.iter().all(|&x| x < 10)); - assert!(!v.iter().all(|&x| x % 2 == 0)); - assert!(!v.iter().all(|&x| x > 100)); - assert!(v[..0].iter().all(|_| panic!())); -} - -#[test] -fn test_any() { - let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); - assert!(v.iter().any(|&x| x < 10)); - assert!(v.iter().any(|&x| x % 2 == 0)); - assert!(!v.iter().any(|&x| x > 100)); - assert!(!v[..0].iter().any(|_| panic!())); -} - -#[test] -fn test_find() { - let v: &[isize] = &[1, 3, 9, 27, 103, 14, 11]; - assert_eq!(*v.iter().find(|&&x| x & 1 == 0).unwrap(), 14); - assert_eq!(*v.iter().find(|&&x| x % 3 == 0).unwrap(), 3); - assert!(v.iter().find(|&&x| x % 12 == 0).is_none()); -} - -#[test] -fn test_try_find() { - let xs: &[isize] = &[]; - assert_eq!(xs.iter().try_find(testfn), Ok(None)); - let xs: &[isize] = &[1, 2, 3, 4]; - assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2))); - let xs: &[isize] = &[1, 3, 4]; - assert_eq!(xs.iter().try_find(testfn), Err(())); - - let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; - let mut iter = xs.iter(); - assert_eq!(iter.try_find(testfn), Ok(Some(&2))); - assert_eq!(iter.try_find(testfn), Err(())); - assert_eq!(iter.next(), Some(&5)); - - fn testfn(x: &&isize) -> Result { - if **x == 2 { - return Ok(true); - } - if **x == 4 { - return Err(()); - } - Ok(false) - } -} - -#[test] -fn test_try_find_api_usability() -> Result<(), Box> { - let a = ["1", "2"]; - - let is_my_num = |s: &str, search: i32| -> Result { - Ok(s.parse::()? == search) - }; - - let val = a.iter().try_find(|&&s| is_my_num(s, 2))?; - assert_eq!(val, Some(&"2")); - - Ok(()) -} - -#[test] -fn test_position() { - let v = &[1, 3, 9, 27, 103, 14, 11]; - assert_eq!(v.iter().position(|x| *x & 1 == 0).unwrap(), 5); - assert_eq!(v.iter().position(|x| *x % 3 == 0).unwrap(), 1); - assert!(v.iter().position(|x| *x % 12 == 0).is_none()); -} - -#[test] -fn test_count() { - let xs = &[1, 2, 2, 1, 5, 9, 0, 2]; - assert_eq!(xs.iter().filter(|x| **x == 2).count(), 3); - assert_eq!(xs.iter().filter(|x| **x == 5).count(), 1); - assert_eq!(xs.iter().filter(|x| **x == 95).count(), 0); -} - -#[test] -fn test_max_by_key() { - let xs: &[isize] = &[-3, 0, 1, 5, -10]; - assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10); -} - -#[test] -fn test_max_by() { - let xs: &[isize] = &[-3, 0, 1, 5, -10]; - assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10); -} - -#[test] -fn test_min_by_key() { - let xs: &[isize] = &[-3, 0, 1, 5, -10]; - assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0); -} - -#[test] -fn test_min_by() { - let xs: &[isize] = &[-3, 0, 1, 5, -10]; - assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0); -} - -#[test] -fn test_by_ref() { - let mut xs = 0..10; - // sum the first five values - let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b); - assert_eq!(partial_sum, 10); - assert_eq!(xs.next(), Some(5)); -} - -#[test] -fn test_is_sorted() { - // Tests on integers - assert!([1, 2, 2, 9].iter().is_sorted()); - assert!(![1, 3, 2].iter().is_sorted()); - assert!([0].iter().is_sorted()); - assert!([0, 0].iter().is_sorted()); - assert!(core::iter::empty::().is_sorted()); - - // Tests on floats - assert!([1.0f32, 2.0, 2.0, 9.0].iter().is_sorted()); - assert!(![1.0f32, 3.0f32, 2.0f32].iter().is_sorted()); - assert!([0.0f32].iter().is_sorted()); - assert!([0.0f32, 0.0f32].iter().is_sorted()); - // Test cases with NaNs - assert!([f32::NAN].iter().is_sorted()); - assert!(![f32::NAN, f32::NAN].iter().is_sorted()); - assert!(![0.0, 1.0, f32::NAN].iter().is_sorted()); - // Tests from - assert!(![f32::NAN, f32::NAN, f32::NAN].iter().is_sorted()); - assert!(![1.0, f32::NAN, 2.0].iter().is_sorted()); - assert!(![2.0, f32::NAN, 1.0].iter().is_sorted()); - assert!(![2.0, f32::NAN, 1.0, 7.0].iter().is_sorted()); - assert!(![2.0, f32::NAN, 1.0, 0.0].iter().is_sorted()); - assert!(![-f32::NAN, -1.0, 0.0, 1.0, f32::NAN].iter().is_sorted()); - assert!(![f32::NAN, -f32::NAN, -1.0, 0.0, 1.0].iter().is_sorted()); - assert!(![1.0, f32::NAN, -f32::NAN, -1.0, 0.0].iter().is_sorted()); - assert!(![0.0, 1.0, f32::NAN, -f32::NAN, -1.0].iter().is_sorted()); - assert!(![-1.0, 0.0, 1.0, f32::NAN, -f32::NAN].iter().is_sorted()); - - // Tests for is_sorted_by - assert!(![6, 2, 8, 5, 1, -60, 1337].iter().is_sorted()); - assert!([6, 2, 8, 5, 1, -60, 1337].iter().is_sorted_by(|_, _| true)); - - // Tests for is_sorted_by_key - assert!([-2, -1, 0, 3].iter().is_sorted()); - assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); - assert!(!["c", "bb", "aaa"].iter().is_sorted()); - assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len())); -} - -#[test] -fn test_partition() { - fn check(xs: &mut [i32], ref p: impl Fn(&i32) -> bool, expected: usize) { - let i = xs.iter_mut().partition_in_place(p); - assert_eq!(expected, i); - assert!(xs[..i].iter().all(p)); - assert!(!xs[i..].iter().any(p)); - assert!(xs.iter().is_partitioned(p)); - if i == 0 || i == xs.len() { - assert!(xs.iter().rev().is_partitioned(p)); - } else { - assert!(!xs.iter().rev().is_partitioned(p)); - } - } - - check(&mut [], |_| true, 0); - check(&mut [], |_| false, 0); - - check(&mut [0], |_| true, 1); - check(&mut [0], |_| false, 0); - - check(&mut [-1, 1], |&x| x > 0, 1); - check(&mut [-1, 1], |&x| x < 0, 1); - - let ref mut xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - check(xs, |_| true, 10); - check(xs, |_| false, 0); - check(xs, |&x| x % 2 == 0, 5); // evens - check(xs, |&x| x % 2 == 1, 5); // odds - check(xs, |&x| x % 3 == 0, 4); // multiple of 3 - check(xs, |&x| x % 4 == 0, 3); // multiple of 4 - check(xs, |&x| x % 5 == 0, 2); // multiple of 5 - check(xs, |&x| x < 3, 3); // small - check(xs, |&x| x > 6, 3); // large -} - -#[test] -fn test_iterator_rev_advance_by() { - let v: &[_] = &[0, 1, 2, 3, 4]; - - for i in 0..v.len() { - let mut iter = v.iter().rev(); - assert_eq!(iter.advance_by(i), Ok(())); - assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]); - assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap())); - } - - assert_eq!(v.iter().rev().advance_by(v.len()), Ok(())); - assert_eq!(v.iter().rev().advance_by(100), Err(NonZero::new(100 - v.len()).unwrap())); -} - -#[test] -fn test_find_map() { - let xs: &[isize] = &[]; - assert_eq!(xs.iter().find_map(half_if_even), None); - let xs: &[isize] = &[3, 5]; - assert_eq!(xs.iter().find_map(half_if_even), None); - let xs: &[isize] = &[4, 5]; - assert_eq!(xs.iter().find_map(half_if_even), Some(2)); - let xs: &[isize] = &[3, 6]; - assert_eq!(xs.iter().find_map(half_if_even), Some(3)); - - let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; - let mut iter = xs.iter(); - assert_eq!(iter.find_map(half_if_even), Some(1)); - assert_eq!(iter.find_map(half_if_even), Some(2)); - assert_eq!(iter.find_map(half_if_even), Some(3)); - assert_eq!(iter.next(), Some(&7)); - - fn half_if_even(x: &isize) -> Option { - if x % 2 == 0 { Some(x / 2) } else { None } - } -} - -#[test] -fn test_try_reduce() { - let v = [1usize, 2, 3, 4, 5]; - let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y)); - assert_eq!(sum, Some(Some(15))); - - let v = [1, 2, 3, 4, 5, usize::MAX]; - let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y)); - assert_eq!(sum, None); - - let v: [usize; 0] = []; - let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y)); - assert_eq!(sum, Some(None)); - - let v = ["1", "2", "3", "4", "5"]; - let max = v.into_iter().try_reduce(|x, y| { - if x.parse::().ok()? > y.parse::().ok()? { Some(x) } else { Some(y) } - }); - assert_eq!(max, Some(Some("5"))); - - let v = ["1", "2", "3", "4", "5"]; - let max: Result, ::Err> = - v.into_iter().try_reduce(|x, y| { - if x.parse::()? > y.parse::()? { Ok(x) } else { Ok(y) } - }); - assert_eq!(max, Ok(Some("5"))); -} - -#[test] -fn test_iterator_len() { - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().count(), 4); - assert_eq!(v[..10].iter().count(), 10); - assert_eq!(v[..0].iter().count(), 0); -} - -#[test] -fn test_collect() { - let a = vec![1, 2, 3, 4, 5]; - let b: Vec = a.iter().cloned().collect(); - assert!(a == b); -} - -#[test] -fn test_try_collect() { - use core::ops::ControlFlow::{Break, Continue}; - - let u = vec![Some(1), Some(2), Some(3)]; - let v = u.into_iter().try_collect::>(); - assert_eq!(v, Some(vec![1, 2, 3])); - - let u = vec![Some(1), Some(2), None, Some(3)]; - let mut it = u.into_iter(); - let v = it.try_collect::>(); - assert_eq!(v, None); - let v = it.try_collect::>(); - assert_eq!(v, Some(vec![3])); - - let u: Vec> = vec![Ok(1), Ok(2), Ok(3)]; - let v = u.into_iter().try_collect::>(); - assert_eq!(v, Ok(vec![1, 2, 3])); - - let u = vec![Ok(1), Ok(2), Err(()), Ok(3)]; - let v = u.into_iter().try_collect::>(); - assert_eq!(v, Err(())); - - let numbers = vec![1, 2, 3, 4, 5]; - let all_positive = numbers - .iter() - .cloned() - .map(|n| if n > 0 { Some(n) } else { None }) - .try_collect::>(); - assert_eq!(all_positive, Some(numbers)); - - let numbers = vec![-2, -1, 0, 1, 2]; - let all_positive = - numbers.into_iter().map(|n| if n > 0 { Some(n) } else { None }).try_collect::>(); - assert_eq!(all_positive, None); - - let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)]; - let mut it = u.into_iter(); - - let v = it.try_collect::>(); - assert_eq!(v, Break(3)); - - let v = it.try_collect::>(); - assert_eq!(v, Continue(vec![4, 5])); -} - -#[test] -fn test_collect_into() { - let a = vec![1, 2, 3, 4, 5]; - let mut b = Vec::new(); - a.iter().cloned().collect_into(&mut b); - assert!(a == b); -} - -#[test] -fn iter_try_collect_uses_try_fold_not_next() { - // This makes sure it picks up optimizations, and doesn't use the `&mut I` impl. - struct PanicOnNext(I); - impl Iterator for PanicOnNext { - type Item = I::Item; - fn next(&mut self) -> Option { - panic!("Iterator::next should not be called!") - } - fn try_fold(&mut self, init: B, f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: std::ops::Try, - { - self.0.try_fold(init, f) - } - } - - let it = (0..10).map(Some); - let _ = PanicOnNext(it).try_collect::>(); - // validation is just that it didn't panic. -} - -#[test] -fn test_next_chunk() { - let mut it = 0..12; - assert_eq!(it.next_chunk().unwrap(), [0, 1, 2, 3]); - assert_eq!(it.next_chunk().unwrap(), []); - assert_eq!(it.next_chunk().unwrap(), [4, 5, 6, 7, 8, 9]); - assert_eq!(it.next_chunk::<4>().unwrap_err().as_slice(), &[10, 11]); - - let mut it = std::iter::repeat_with(|| panic!()); - assert_eq!(it.next_chunk::<0>().unwrap(), []); -} - -#[test] -fn test_collect_into_tuples() { - let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)]; - let b = vec![1, 4, 7]; - let c = vec![2, 5, 8]; - let d = vec![3, 6, 9]; - let mut e = (Vec::new(), Vec::new(), Vec::new()); - a.iter().cloned().collect_into(&mut e); - assert!(e.0 == b); - assert!(e.1 == c); - assert!(e.2 == d); -} - -#[test] -fn test_collect_for_tuples() { - let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)]; - let b = vec![1, 4, 7]; - let c = vec![2, 5, 8]; - let d = vec![3, 6, 9]; - let e: (Vec<_>, Vec<_>, Vec<_>) = a.into_iter().collect(); - assert!(e.0 == b); - assert!(e.1 == c); - assert!(e.2 == d); -} - -// just tests by whether or not this compiles -fn _empty_impl_all_auto_traits() { - use std::panic::{RefUnwindSafe, UnwindSafe}; - fn all_auto_traits() {} - - all_auto_traits::>(); -} diff --git a/library/core/tests/iter/traits/mod.rs b/library/core/tests/iter/traits/mod.rs deleted file mode 100644 index 80619f53f25..00000000000 --- a/library/core/tests/iter/traits/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod accum; -mod double_ended; -mod iterator; -mod step; diff --git a/library/core/tests/iter/traits/step.rs b/library/core/tests/iter/traits/step.rs deleted file mode 100644 index bf935af397c..00000000000 --- a/library/core/tests/iter/traits/step.rs +++ /dev/null @@ -1,100 +0,0 @@ -use core::iter::*; - -#[test] -fn test_steps_between() { - assert_eq!(Step::steps_between(&20_u8, &200_u8), (180_usize, Some(180_usize))); - assert_eq!(Step::steps_between(&-20_i8, &80_i8), (100_usize, Some(100_usize))); - assert_eq!(Step::steps_between(&-120_i8, &80_i8), (200_usize, Some(200_usize))); - assert_eq!( - Step::steps_between(&20_u32, &4_000_100_u32), - (4_000_080_usize, Some(4_000_080_usize)) - ); - assert_eq!(Step::steps_between(&-20_i32, &80_i32), (100_usize, Some(100_usize))); - assert_eq!( - Step::steps_between(&-2_000_030_i32, &2_000_050_i32), - (4_000_080_usize, Some(4_000_080_usize)) - ); - - // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms - - assert_eq!(Step::steps_between(&20_u128, &200_u128), (180_usize, Some(180_usize))); - assert_eq!(Step::steps_between(&-20_i128, &80_i128), (100_usize, Some(100_usize))); - if cfg!(target_pointer_width = "64") { - assert_eq!( - Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), - (usize::MAX, Some(usize::MAX)) - ); - } - assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), (usize::MAX, None)); - assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), (usize::MAX, None)); - assert_eq!( - Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,), - (usize::MAX, None), - ); - - assert_eq!(Step::steps_between(&100_u32, &10_u32), (0, None)); -} - -#[test] -fn test_step_forward() { - assert_eq!(Step::forward_checked(55_u8, 200_usize), Some(255_u8)); - assert_eq!(Step::forward_checked(252_u8, 200_usize), None); - assert_eq!(Step::forward_checked(0_u8, 256_usize), None); - assert_eq!(Step::forward_checked(-110_i8, 200_usize), Some(90_i8)); - assert_eq!(Step::forward_checked(-110_i8, 248_usize), None); - assert_eq!(Step::forward_checked(-126_i8, 256_usize), None); - - assert_eq!(Step::forward_checked(35_u16, 100_usize), Some(135_u16)); - assert_eq!(Step::forward_checked(35_u16, 65500_usize), Some(u16::MAX)); - assert_eq!(Step::forward_checked(36_u16, 65500_usize), None); - assert_eq!(Step::forward_checked(-110_i16, 200_usize), Some(90_i16)); - assert_eq!(Step::forward_checked(-20_030_i16, 50_050_usize), Some(30_020_i16)); - assert_eq!(Step::forward_checked(-10_i16, 40_000_usize), None); - assert_eq!(Step::forward_checked(-10_i16, 70_000_usize), None); - - assert_eq!(Step::forward_checked(10_u128, 70_000_usize), Some(70_010_u128)); - assert_eq!(Step::forward_checked(10_i128, 70_030_usize), Some(70_040_i128)); - assert_eq!( - Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0xff_usize), - Some(u128::MAX), - ); - assert_eq!( - Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0x100_usize), - None - ); - assert_eq!( - Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0xff_usize), - Some(i128::MAX), - ); - assert_eq!( - Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize), - None - ); -} - -#[test] -fn test_step_backward() { - assert_eq!(Step::backward_checked(255_u8, 200_usize), Some(55_u8)); - assert_eq!(Step::backward_checked(100_u8, 200_usize), None); - assert_eq!(Step::backward_checked(255_u8, 256_usize), None); - assert_eq!(Step::backward_checked(90_i8, 200_usize), Some(-110_i8)); - assert_eq!(Step::backward_checked(110_i8, 248_usize), None); - assert_eq!(Step::backward_checked(127_i8, 256_usize), None); - - assert_eq!(Step::backward_checked(135_u16, 100_usize), Some(35_u16)); - assert_eq!(Step::backward_checked(u16::MAX, 65500_usize), Some(35_u16)); - assert_eq!(Step::backward_checked(10_u16, 11_usize), None); - assert_eq!(Step::backward_checked(90_i16, 200_usize), Some(-110_i16)); - assert_eq!(Step::backward_checked(30_020_i16, 50_050_usize), Some(-20_030_i16)); - assert_eq!(Step::backward_checked(-10_i16, 40_000_usize), None); - assert_eq!(Step::backward_checked(-10_i16, 70_000_usize), None); - - assert_eq!(Step::backward_checked(70_010_u128, 70_000_usize), Some(10_u128)); - assert_eq!(Step::backward_checked(70_020_i128, 70_030_usize), Some(-10_i128)); - assert_eq!(Step::backward_checked(10_u128, 7_usize), Some(3_u128)); - assert_eq!(Step::backward_checked(10_u128, 11_usize), None); - assert_eq!( - Step::backward_checked(-0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize), - Some(i128::MIN) - ); -} diff --git a/library/core/tests/lazy.rs b/library/core/tests/lazy.rs deleted file mode 100644 index 32d0ac51f03..00000000000 --- a/library/core/tests/lazy.rs +++ /dev/null @@ -1,167 +0,0 @@ -use core::cell::{Cell, LazyCell, OnceCell}; -use core::sync::atomic::AtomicUsize; -use core::sync::atomic::Ordering::SeqCst; - -#[test] -fn once_cell() { - let c = OnceCell::new(); - assert!(c.get().is_none()); - c.get_or_init(|| 92); - assert_eq!(c.get(), Some(&92)); - - c.get_or_init(|| panic!("Kaboom!")); - assert_eq!(c.get(), Some(&92)); -} - -#[test] -fn once_cell_get_mut() { - let mut c = OnceCell::new(); - assert!(c.get_mut().is_none()); - c.set(90).unwrap(); - *c.get_mut().unwrap() += 2; - assert_eq!(c.get_mut(), Some(&mut 92)); -} - -#[test] -fn once_cell_drop() { - static DROP_CNT: AtomicUsize = AtomicUsize::new(0); - struct Dropper; - impl Drop for Dropper { - fn drop(&mut self) { - DROP_CNT.fetch_add(1, SeqCst); - } - } - - let x = OnceCell::new(); - x.get_or_init(|| Dropper); - assert_eq!(DROP_CNT.load(SeqCst), 0); - drop(x); - assert_eq!(DROP_CNT.load(SeqCst), 1); -} - -#[test] -fn unsync_once_cell_drop_empty() { - let x = OnceCell::<&'static str>::new(); - drop(x); -} - -/* FIXME(#110395) -#[test] -const fn once_cell_const() { - let _once_cell: OnceCell = OnceCell::new(); - let _once_cell: OnceCell = OnceCell::from(32); -} -*/ - -#[test] -fn clone() { - let s = OnceCell::new(); - let c = s.clone(); - assert!(c.get().is_none()); - - s.set("hello").unwrap(); - let c = s.clone(); - assert_eq!(c.get().map(|c| *c), Some("hello")); -} - -#[test] -fn from_impl() { - assert_eq!(OnceCell::from("value").get(), Some(&"value")); - assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); -} - -#[test] -fn partialeq_impl() { - assert!(OnceCell::from("value") == OnceCell::from("value")); - assert!(OnceCell::from("foo") != OnceCell::from("bar")); - - assert!(OnceCell::<&'static str>::new() == OnceCell::new()); - assert!(OnceCell::<&'static str>::new() != OnceCell::from("value")); -} - -#[test] -fn into_inner() { - let cell: OnceCell<&'static str> = OnceCell::new(); - assert_eq!(cell.into_inner(), None); - let cell = OnceCell::new(); - cell.set("hello").unwrap(); - assert_eq!(cell.into_inner(), Some("hello")); -} - -#[test] -fn lazy_new() { - let called = Cell::new(0); - let x = LazyCell::new(|| { - called.set(called.get() + 1); - 92 - }); - - assert_eq!(called.get(), 0); - - let y = *x - 30; - assert_eq!(y, 62); - assert_eq!(called.get(), 1); - - let y = *x - 30; - assert_eq!(y, 62); - assert_eq!(called.get(), 1); -} - -// Check that we can infer `T` from closure's type. -#[test] -fn lazy_type_inference() { - let _ = LazyCell::new(|| ()); -} - -#[test] -#[cfg(panic = "unwind")] -#[should_panic = "LazyCell instance has previously been poisoned"] -fn lazy_force_mut_panic() { - let mut lazy = LazyCell::::new(|| panic!()); - std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - let _ = LazyCell::force_mut(&mut lazy); - })) - .unwrap_err(); - let _ = &*lazy; -} - -#[test] -fn lazy_force_mut() { - let s = "abc".to_owned(); - let mut lazy = LazyCell::new(move || s); - LazyCell::force_mut(&mut lazy); - let p = LazyCell::force_mut(&mut lazy); - p.clear(); - LazyCell::force_mut(&mut lazy); -} - -#[test] -fn aliasing_in_get() { - let x = OnceCell::new(); - x.set(42).unwrap(); - let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option` --+ - let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option` | - println!("{at_x}"); // <------- up until here ---------------------------+ -} - -#[test] -#[should_panic(expected = "reentrant init")] -fn reentrant_init() { - let x: OnceCell> = OnceCell::new(); - let dangling_ref: Cell> = Cell::new(None); - x.get_or_init(|| { - let r = x.get_or_init(|| Box::new(92)); - dangling_ref.set(Some(r)); - Box::new(62) - }); - eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); -} - -#[test] -fn dropck() { - let cell = OnceCell::new(); - { - let s = String::new(); - cell.set(&s).unwrap(); - } -} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs deleted file mode 100644 index a8980c5f30a..00000000000 --- a/library/core/tests/lib.rs +++ /dev/null @@ -1,194 +0,0 @@ -// tidy-alphabetical-start -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] -#![cfg_attr(test, feature(cfg_match))] -#![feature(alloc_layout_extra)] -#![feature(array_chunks)] -#![feature(array_ptr_get)] -#![feature(array_try_from_fn)] -#![feature(array_windows)] -#![feature(ascii_char)] -#![feature(ascii_char_variants)] -#![feature(async_iter_from_iter)] -#![feature(async_iterator)] -#![feature(bigint_helper_methods)] -#![feature(cell_update)] -#![feature(clone_to_uninit)] -#![feature(const_black_box)] -#![feature(const_eval_select)] -#![feature(const_swap_nonoverlapping)] -#![feature(const_trait_impl)] -#![feature(core_intrinsics)] -#![feature(core_intrinsics_fallbacks)] -#![feature(core_io_borrowed_buf)] -#![feature(core_private_bignum)] -#![feature(core_private_diy_float)] -#![feature(dec2flt)] -#![feature(duration_constants)] -#![feature(duration_constructors)] -#![feature(error_generic_member_access)] -#![feature(exact_size_is_empty)] -#![feature(extern_types)] -#![feature(float_minimum_maximum)] -#![feature(flt2dec)] -#![feature(fmt_internals)] -#![feature(formatting_options)] -#![feature(freeze)] -#![feature(future_join)] -#![feature(generic_assert_internals)] -#![feature(get_many_mut)] -#![feature(hasher_prefixfree_extras)] -#![feature(hashmap_internals)] -#![feature(inline_const_pat)] -#![feature(int_roundings)] -#![feature(ip)] -#![feature(ip_from)] -#![feature(is_ascii_octdigit)] -#![feature(iter_advance_by)] -#![feature(iter_array_chunks)] -#![feature(iter_chain)] -#![feature(iter_collect_into)] -#![feature(iter_intersperse)] -#![feature(iter_is_partitioned)] -#![feature(iter_map_windows)] -#![feature(iter_next_chunk)] -#![feature(iter_order_by)] -#![feature(iter_partition_in_place)] -#![feature(iterator_try_collect)] -#![feature(iterator_try_reduce)] -#![feature(layout_for_ptr)] -#![feature(lazy_get)] -#![feature(maybe_uninit_fill)] -#![feature(maybe_uninit_uninit_array_transpose)] -#![feature(maybe_uninit_write_slice)] -#![feature(min_specialization)] -#![feature(never_type)] -#![feature(num_midpoint_signed)] -#![feature(numfmt)] -#![feature(pattern)] -#![feature(pointer_is_aligned_to)] -#![feature(portable_simd)] -#![feature(ptr_metadata)] -#![feature(slice_from_ptr_range)] -#![feature(slice_internals)] -#![feature(slice_partition_dedup)] -#![feature(slice_split_once)] -#![feature(slice_take)] -#![feature(split_array)] -#![feature(split_as_slice)] -#![feature(std_internals)] -#![feature(step_trait)] -#![feature(str_internals)] -#![feature(strict_provenance_atomic_ptr)] -#![feature(strict_provenance_lints)] -#![feature(test)] -#![feature(trait_upcasting)] -#![feature(trusted_len)] -#![feature(trusted_random_access)] -#![feature(try_blocks)] -#![feature(try_find)] -#![feature(try_trait_v2)] -#![feature(unsigned_is_multiple_of)] -#![feature(unsize)] -#![feature(unsized_tuple_coercion)] -#![feature(unwrap_infallible)] -// tidy-alphabetical-end -#![allow(internal_features)] -#![deny(fuzzy_provenance_casts)] -#![deny(unsafe_op_in_unsafe_fn)] - -/// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality. -macro_rules! assert_eq_const_safe { - ($left:expr, $right:expr) => { - assert_eq_const_safe!($left, $right, concat!(stringify!($left), " == ", stringify!($right))); - }; - ($left:expr, $right:expr$(, $($arg:tt)+)?) => { - { - fn runtime() { - assert_eq!($left, $right, $($($arg)*),*); - } - const fn compiletime() { - assert!(matches!($left, const { $right })); - } - core::intrinsics::const_eval_select((), compiletime, runtime) - } - }; -} - -/// Creates a test for runtime and a test for constant-time. -macro_rules! test_runtime_and_compiletime { - ($( - $(#[$attr:meta])* - fn $test:ident() $block:block - )*) => { - $( - $(#[$attr])* - #[test] - fn $test() $block - $(#[$attr])* - const _: () = $block; - )* - } -} - -mod alloc; -mod any; -mod array; -mod ascii; -mod ascii_char; -mod asserting; -mod async_iter; -mod atomic; -mod bool; -mod cell; -mod char; -mod clone; -mod cmp; -mod const_ptr; -mod convert; -mod ffi; -mod fmt; -mod future; -mod hash; -mod intrinsics; -mod io; -mod iter; -mod lazy; -#[cfg(not(bootstrap))] -mod macros; -#[cfg(bootstrap)] -mod macros_bootstrap; -mod manually_drop; -mod mem; -mod net; -mod nonzero; -mod num; -mod ops; -mod option; -mod panic; -mod pattern; -mod pin; -mod pin_macro; -mod ptr; -mod result; -mod simd; -mod slice; -mod str; -mod str_lossy; -mod task; -mod time; -mod tuple; -mod unicode; -mod waker; - -/// Copied from `std::test_helpers::test_rng`, see that function for rationale. -#[track_caller] -#[allow(dead_code)] // Not used in all configurations. -pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { - use core::hash::{BuildHasher, Hash, Hasher}; - let mut hasher = std::hash::RandomState::new().build_hasher(); - core::panic::Location::caller().hash(&mut hasher); - let hc64 = hasher.finish(); - let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); - let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); - rand::SeedableRng::from_seed(seed) -} diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs deleted file mode 100644 index b30a40b7df2..00000000000 --- a/library/core/tests/macros.rs +++ /dev/null @@ -1,206 +0,0 @@ -#![allow(unused_must_use)] - -#[allow(dead_code)] -trait Trait { - fn blah(&self); -} - -#[allow(dead_code)] -struct Struct; - -impl Trait for Struct { - cfg_match! { - feature = "blah" => { - fn blah(&self) { - unimplemented!(); - } - } - _ => { - fn blah(&self) { - unimplemented!(); - } - } - } -} - -#[test] -fn assert_eq_trailing_comma() { - assert_eq!(1, 1,); -} - -#[test] -fn assert_escape() { - assert!(r#"☃\backslash"#.contains("\\")); -} - -#[test] -fn assert_ne_trailing_comma() { - assert_ne!(1, 2,); -} - -#[rustfmt::skip] -#[test] -fn matches_leading_pipe() { - matches!(1, | 1 | 2 | 3); -} - -#[test] -fn cfg_match_basic() { - cfg_match! { - target_pointer_width = "64" => { fn f0_() -> bool { true }} - } - - cfg_match! { - unix => { fn f1_() -> bool { true } } - any(target_os = "macos", target_os = "linux") => { fn f1_() -> bool { false }} - } - - cfg_match! { - target_pointer_width = "32" => { fn f2_() -> bool { false } } - target_pointer_width = "64" => { fn f2_() -> bool { true } } - } - - cfg_match! { - target_pointer_width = "16" => { fn f3_() -> i32 { 1 } } - _ => { fn f3_() -> i32 { 2 }} - } - - #[cfg(target_pointer_width = "64")] - assert!(f0_()); - - #[cfg(unix)] - assert!(f1_()); - - #[cfg(target_pointer_width = "32")] - assert!(!f2_()); - #[cfg(target_pointer_width = "64")] - assert!(f2_()); - - #[cfg(not(target_pointer_width = "16"))] - assert_eq!(f3_(), 2); -} - -#[test] -fn cfg_match_debug_assertions() { - cfg_match! { - debug_assertions => { - assert!(cfg!(debug_assertions)); - assert_eq!(4, 2+2); - } - _ => { - assert!(cfg!(not(debug_assertions))); - assert_eq!(10, 5+5); - } - } -} - -#[cfg(target_pointer_width = "64")] -#[test] -fn cfg_match_no_duplication_on_64() { - cfg_match! { - windows => { - fn foo() {} - } - unix => { - fn foo() {} - } - target_pointer_width = "64" => { - fn foo() {} - } - } - foo(); -} - -#[test] -fn cfg_match_options() { - cfg_match! { - test => { - use core::option::Option as Option2; - fn works1() -> Option2 { Some(1) } - } - _ => { fn works1() -> Option { None } } - } - - cfg_match! { - feature = "foo" => { fn works2() -> bool { false } } - test => { fn works2() -> bool { true } } - _ => { fn works2() -> bool { false } } - } - - cfg_match! { - feature = "foo" => { fn works3() -> bool { false } } - _ => { fn works3() -> bool { true } } - } - - cfg_match! { - test => { - use core::option::Option as Option3; - fn works4() -> Option3 { Some(1) } - } - } - - cfg_match! { - feature = "foo" => { fn works5() -> bool { false } } - test => { fn works5() -> bool { true } } - } - - assert!(works1().is_some()); - assert!(works2()); - assert!(works3()); - assert!(works4().is_some()); - assert!(works5()); -} - -#[test] -fn cfg_match_two_functions() { - cfg_match! { - target_pointer_width = "64" => { - fn foo1() {} - fn bar1() {} - } - _ => { - fn foo2() {} - fn bar2() {} - } - } - - #[cfg(target_pointer_width = "64")] - { - foo1(); - bar1(); - } - #[cfg(not(target_pointer_width = "64"))] - { - foo2(); - bar2(); - } -} - -fn _accepts_expressions() -> i32 { - cfg_match! { - unix => { 1 } - _ => { 2 } - } -} - -// The current implementation expands to a macro call, which allows the use of expression -// statements. -fn _allows_stmt_expr_attributes() { - let one = 1; - let two = 2; - cfg_match! { - unix => { one * two; } - _ => { one + two; } - } -} - -fn _expression() { - let _ = cfg_match!({ - windows => { - " XP" - } - _ => { - "" - } - }); -} diff --git a/library/core/tests/macros_bootstrap.rs b/library/core/tests/macros_bootstrap.rs deleted file mode 100644 index f10ef862c5d..00000000000 --- a/library/core/tests/macros_bootstrap.rs +++ /dev/null @@ -1,193 +0,0 @@ -#![allow(unused_must_use)] - -#[allow(dead_code)] -trait Trait { - fn blah(&self); -} - -#[allow(dead_code)] -struct Struct; - -impl Trait for Struct { - cfg_match! { - cfg(feature = "blah") => { - fn blah(&self) { - unimplemented!(); - } - } - _ => { - fn blah(&self) { - unimplemented!(); - } - } - } -} - -#[test] -fn assert_eq_trailing_comma() { - assert_eq!(1, 1,); -} - -#[test] -fn assert_escape() { - assert!(r#"☃\backslash"#.contains("\\")); -} - -#[test] -fn assert_ne_trailing_comma() { - assert_ne!(1, 2,); -} - -#[rustfmt::skip] -#[test] -fn matches_leading_pipe() { - matches!(1, | 1 | 2 | 3); -} - -#[test] -fn cfg_match_basic() { - cfg_match! { - cfg(target_pointer_width = "64") => { fn f0_() -> bool { true }} - } - - cfg_match! { - cfg(unix) => { fn f1_() -> bool { true }} - cfg(any(target_os = "macos", target_os = "linux")) => { fn f1_() -> bool { false }} - } - - cfg_match! { - cfg(target_pointer_width = "32") => { fn f2_() -> bool { false }} - cfg(target_pointer_width = "64") => { fn f2_() -> bool { true }} - } - - cfg_match! { - cfg(target_pointer_width = "16") => { fn f3_() -> i32 { 1 }} - _ => { fn f3_() -> i32 { 2 }} - } - - #[cfg(target_pointer_width = "64")] - assert!(f0_()); - - #[cfg(unix)] - assert!(f1_()); - - #[cfg(target_pointer_width = "32")] - assert!(!f2_()); - #[cfg(target_pointer_width = "64")] - assert!(f2_()); - - #[cfg(not(target_pointer_width = "16"))] - assert_eq!(f3_(), 2); -} - -#[test] -fn cfg_match_debug_assertions() { - cfg_match! { - cfg(debug_assertions) => { - assert!(cfg!(debug_assertions)); - assert_eq!(4, 2+2); - } - _ => { - assert!(cfg!(not(debug_assertions))); - assert_eq!(10, 5+5); - } - } -} - -#[cfg(target_pointer_width = "64")] -#[test] -fn cfg_match_no_duplication_on_64() { - cfg_match! { - cfg(windows) => { - fn foo() {} - } - cfg(unix) => { - fn foo() {} - } - cfg(target_pointer_width = "64") => { - fn foo() {} - } - } - foo(); -} - -#[test] -fn cfg_match_options() { - cfg_match! { - cfg(test) => { - use core::option::Option as Option2; - fn works1() -> Option2 { Some(1) } - } - _ => { fn works1() -> Option { None } } - } - - cfg_match! { - cfg(feature = "foo") => { fn works2() -> bool { false } } - cfg(test) => { fn works2() -> bool { true } } - _ => { fn works2() -> bool { false } } - } - - cfg_match! { - cfg(feature = "foo") => { fn works3() -> bool { false } } - _ => { fn works3() -> bool { true } } - } - - cfg_match! { - cfg(test) => { - use core::option::Option as Option3; - fn works4() -> Option3 { Some(1) } - } - } - - cfg_match! { - cfg(feature = "foo") => { fn works5() -> bool { false } } - cfg(test) => { fn works5() -> bool { true } } - } - - assert!(works1().is_some()); - assert!(works2()); - assert!(works3()); - assert!(works4().is_some()); - assert!(works5()); -} - -#[test] -fn cfg_match_two_functions() { - cfg_match! { - cfg(target_pointer_width = "64") => { - fn foo1() {} - fn bar1() {} - } - _ => { - fn foo2() {} - fn bar2() {} - } - } - - #[cfg(target_pointer_width = "64")] - { - foo1(); - bar1(); - } - #[cfg(not(target_pointer_width = "64"))] - { - foo2(); - bar2(); - } -} - -fn _accepts_expressions() -> i32 { - cfg_match! { - cfg(unix) => { 1 } - _ => { 2 } - } -} - -fn _allows_stmt_expr_attributes() { - let one = 1; - let two = 2; - cfg_match! { - cfg(unix) => { one * two; } - _ => { one + two; } - } -} diff --git a/library/core/tests/manually_drop.rs b/library/core/tests/manually_drop.rs deleted file mode 100644 index bbf444471ad..00000000000 --- a/library/core/tests/manually_drop.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![allow(undropped_manually_drops)] - -use core::mem::ManuallyDrop; - -#[test] -fn smoke() { - #[derive(Clone)] - struct TypeWithDrop; - impl Drop for TypeWithDrop { - fn drop(&mut self) { - unreachable!("Should not get dropped"); - } - } - - let x = ManuallyDrop::new(TypeWithDrop); - drop(x); - - // also test unsizing - let x: Box> = - Box::new(ManuallyDrop::new([TypeWithDrop, TypeWithDrop])); - drop(x); - - // test clone and clone_from implementations - let mut x = ManuallyDrop::new(TypeWithDrop); - let y = x.clone(); - x.clone_from(&y); - drop(x); - drop(y); -} diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs deleted file mode 100644 index 1b5c5fc82a6..00000000000 --- a/library/core/tests/mem.rs +++ /dev/null @@ -1,797 +0,0 @@ -use core::mem::*; -use core::ptr; -#[cfg(panic = "unwind")] -use std::rc::Rc; - -#[test] -fn size_of_basic() { - assert_eq!(size_of::(), 1); - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 8); -} - -#[test] -#[cfg(target_pointer_width = "16")] -fn size_of_16() { - assert_eq!(size_of::(), 2); - assert_eq!(size_of::<*const usize>(), 2); -} - -#[test] -#[cfg(target_pointer_width = "32")] -fn size_of_32() { - assert_eq!(size_of::(), 4); - assert_eq!(size_of::<*const usize>(), 4); -} - -#[test] -#[cfg(target_pointer_width = "64")] -fn size_of_64() { - assert_eq!(size_of::(), 8); - assert_eq!(size_of::<*const usize>(), 8); -} - -#[test] -fn size_of_val_basic() { - assert_eq!(size_of_val(&1u8), 1); - assert_eq!(size_of_val(&1u16), 2); - assert_eq!(size_of_val(&1u32), 4); - assert_eq!(size_of_val(&1u64), 8); -} - -#[test] -fn align_of_basic() { - assert_eq!(align_of::(), 1); - assert_eq!(align_of::(), 2); - assert_eq!(align_of::(), 4); -} - -#[test] -#[cfg(target_pointer_width = "16")] -fn align_of_16() { - assert_eq!(align_of::(), 2); - assert_eq!(align_of::<*const usize>(), 2); -} - -#[test] -#[cfg(target_pointer_width = "32")] -fn align_of_32() { - assert_eq!(align_of::(), 4); - assert_eq!(align_of::<*const usize>(), 4); -} - -#[test] -#[cfg(target_pointer_width = "64")] -fn align_of_64() { - assert_eq!(align_of::(), 8); - assert_eq!(align_of::<*const usize>(), 8); -} - -#[test] -fn align_of_val_basic() { - assert_eq!(align_of_val(&1u8), 1); - assert_eq!(align_of_val(&1u16), 2); - assert_eq!(align_of_val(&1u32), 4); -} - -#[test] -fn align_of_val_raw_packed() { - #[repr(C, packed)] - struct B { - f: [u32], - } - let storage = [0u8; 4]; - let b: *const B = ptr::from_raw_parts(storage.as_ptr(), 1); - assert_eq!(unsafe { align_of_val_raw(b) }, 1); - - const ALIGN_OF_VAL_RAW: usize = { - let storage = [0u8; 4]; - let b: *const B = ptr::from_raw_parts(storage.as_ptr(), 1); - unsafe { align_of_val_raw(b) } - }; - assert_eq!(ALIGN_OF_VAL_RAW, 1); -} - -#[test] -fn test_swap() { - let mut x = 31337; - let mut y = 42; - swap(&mut x, &mut y); - assert_eq!(x, 42); - assert_eq!(y, 31337); -} - -#[test] -fn test_replace() { - let mut x = Some("test".to_string()); - let y = replace(&mut x, None); - assert!(x.is_none()); - assert!(y.is_some()); -} - -#[test] -fn test_transmute_copy() { - assert_eq!(1, unsafe { transmute_copy(&1) }); -} - -#[test] -fn test_transmute_copy_shrink() { - assert_eq!(0_u8, unsafe { transmute_copy(&0_u64) }); -} - -#[test] -fn test_transmute_copy_unaligned() { - #[repr(C)] - #[derive(Default)] - struct Unaligned { - a: u8, - b: [u8; 8], - } - - let u = Unaligned::default(); - assert_eq!(0_u64, unsafe { transmute_copy(&u.b) }); -} - -#[test] -#[cfg(panic = "unwind")] -fn test_transmute_copy_grow_panics() { - use std::panic; - - let err = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { - let _unused: u64 = transmute_copy(&1_u8); - })); - - match err { - Ok(_) => unreachable!(), - Err(payload) => { - payload - .downcast::<&'static str>() - .and_then(|s| { - if *s == "cannot transmute_copy if Dst is larger than Src" { - Ok(s) - } else { - Err(s) - } - }) - .unwrap_or_else(|p| panic::resume_unwind(p)); - } - } -} - -#[test] -#[allow(dead_code)] -fn test_discriminant_send_sync() { - enum Regular { - A, - B(i32), - } - enum NotSendSync { - A(*const i32), - } - - fn is_send_sync() {} - - is_send_sync::>(); - is_send_sync::>(); -} - -#[test] -fn assume_init_good() { - const TRUE: bool = unsafe { MaybeUninit::::new(true).assume_init() }; - - assert!(TRUE); -} - -#[test] -fn uninit_array_assume_init() { - let mut array = [MaybeUninit::::uninit(); 5]; - array[0].write(3); - array[1].write(1); - array[2].write(4); - array[3].write(1); - array[4].write(5); - - let array = unsafe { array.transpose().assume_init() }; - - assert_eq!(array, [3, 1, 4, 1, 5]); - - let [] = unsafe { [MaybeUninit::::uninit(); 0].transpose().assume_init() }; -} - -#[test] -fn uninit_write_copy_of_slice() { - let mut dst = [MaybeUninit::new(255); 64]; - let src = [0; 64]; - - assert_eq!(dst.write_copy_of_slice(&src), &src); -} - -#[test] -#[should_panic(expected = "source slice length (32) does not match destination slice length (64)")] -fn uninit_write_copy_of_slice_panic_lt() { - let mut dst = [MaybeUninit::uninit(); 64]; - let src = [0; 32]; - - dst.write_copy_of_slice(&src); -} - -#[test] -#[should_panic(expected = "source slice length (128) does not match destination slice length (64)")] -fn uninit_write_copy_of_slice_panic_gt() { - let mut dst = [MaybeUninit::uninit(); 64]; - let src = [0; 128]; - - dst.write_copy_of_slice(&src); -} - -#[test] -fn uninit_write_clone_of_slice() { - let mut dst = [MaybeUninit::new(255); 64]; - let src = [0; 64]; - - assert_eq!(dst.write_clone_of_slice(&src), &src); -} - -#[test] -#[should_panic(expected = "destination and source slices have different lengths")] -fn uninit_write_clone_of_slice_panic_lt() { - let mut dst = [MaybeUninit::uninit(); 64]; - let src = [0; 32]; - - dst.write_clone_of_slice(&src); -} - -#[test] -#[should_panic(expected = "destination and source slices have different lengths")] -fn uninit_write_clone_of_slice_panic_gt() { - let mut dst = [MaybeUninit::uninit(); 64]; - let src = [0; 128]; - - dst.write_clone_of_slice(&src); -} - -#[test] -#[cfg(panic = "unwind")] -fn uninit_write_clone_of_slice_mid_panic() { - use std::panic; - - enum IncrementOrPanic { - Increment(Rc<()>), - ExpectedPanic, - UnexpectedPanic, - } - - impl Clone for IncrementOrPanic { - fn clone(&self) -> Self { - match self { - Self::Increment(rc) => Self::Increment(rc.clone()), - Self::ExpectedPanic => panic!("expected panic on clone"), - Self::UnexpectedPanic => panic!("unexpected panic on clone"), - } - } - } - - let rc = Rc::new(()); - - let mut dst = [ - MaybeUninit::uninit(), - MaybeUninit::uninit(), - MaybeUninit::uninit(), - MaybeUninit::uninit(), - ]; - - let src = [ - IncrementOrPanic::Increment(rc.clone()), - IncrementOrPanic::Increment(rc.clone()), - IncrementOrPanic::ExpectedPanic, - IncrementOrPanic::UnexpectedPanic, - ]; - - let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { - dst.write_clone_of_slice(&src); - })); - - drop(src); - - match err { - Ok(_) => unreachable!(), - Err(payload) => { - payload - .downcast::<&'static str>() - .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) - .unwrap_or_else(|p| panic::resume_unwind(p)); - - assert_eq!(Rc::strong_count(&rc), 1) - } - } -} - -#[derive(Clone)] -struct Bomb; - -impl Drop for Bomb { - fn drop(&mut self) { - panic!("dropped a bomb! kaboom!") - } -} - -#[test] -fn uninit_write_clone_of_slice_no_drop() { - let mut dst = [MaybeUninit::uninit()]; - let src = [Bomb]; - - dst.write_clone_of_slice(&src); - - forget(src); -} - -#[test] -fn uninit_fill() { - let mut dst = [MaybeUninit::new(255); 64]; - let expect = [0; 64]; - - assert_eq!(MaybeUninit::fill(&mut dst, 0), &expect); -} - -#[cfg(panic = "unwind")] -struct CloneUntilPanic { - limit: usize, - rc: Rc<()>, -} - -#[cfg(panic = "unwind")] -impl Clone for CloneUntilPanic { - fn clone(&self) -> Self { - if Rc::strong_count(&self.rc) >= self.limit { - panic!("expected panic on clone"); - } - Self { limit: self.limit, rc: self.rc.clone() } - } -} - -#[test] -#[cfg(panic = "unwind")] -fn uninit_fill_clone_panic_drop() { - use std::panic; - - let rc = Rc::new(()); - - let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; - - let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; - let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { - MaybeUninit::fill(&mut dst, src); - })); - - match err { - Ok(_) => unreachable!(), - Err(payload) => { - payload - .downcast::<&'static str>() - .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) - .unwrap_or_else(|p| panic::resume_unwind(p)); - assert_eq!(Rc::strong_count(&rc), 1) - } - } -} - -#[test] -#[cfg(panic = "unwind")] -fn uninit_fill_clone_no_drop_clones() { - let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; - - MaybeUninit::fill(&mut dst, Bomb); -} - -#[test] -fn uninit_fill_with() { - let mut dst = [MaybeUninit::new(255); 64]; - let expect = [0; 64]; - - assert_eq!(MaybeUninit::fill_with(&mut dst, || 0), &expect); -} - -#[test] -#[cfg(panic = "unwind")] -fn uninit_fill_with_mid_panic() { - use std::panic; - - let rc = Rc::new(()); - - let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; - - let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; - let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { - MaybeUninit::fill_with(&mut dst, || src.clone()); - })); - - drop(src); - - match err { - Ok(_) => unreachable!(), - Err(payload) => { - payload - .downcast::<&'static str>() - .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) - .unwrap_or_else(|p| panic::resume_unwind(p)); - - assert_eq!(Rc::strong_count(&rc), 1) - } - } -} - -#[test] -#[cfg(panic = "unwind")] -fn uninit_fill_with_no_drop() { - let mut dst = [MaybeUninit::uninit()]; - let src = Bomb; - - MaybeUninit::fill_with(&mut dst, || src.clone()); - - forget(src); -} - -#[test] -fn uninit_fill_from() { - let mut dst = [MaybeUninit::new(255); 64]; - let src = [0; 64]; - - let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); - assert_eq!(initted, &src); - assert_eq!(remainder.len(), 0); -} - -#[test] -fn uninit_fill_from_partial() { - let mut dst = [MaybeUninit::new(255); 64]; - let src = [0; 48]; - - let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); - assert_eq!(initted, &src); - assert_eq!(remainder.len(), 16); -} - -#[test] -fn uninit_over_fill() { - let mut dst = [MaybeUninit::new(255); 64]; - let src = [0; 72]; - - let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); - assert_eq!(initted, &src[0..64]); - assert_eq!(remainder.len(), 0); -} - -#[test] -fn uninit_empty_fill() { - let mut dst = [MaybeUninit::new(255); 64]; - let src = [0; 0]; - - let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); - assert_eq!(initted, &src[0..0]); - assert_eq!(remainder.len(), 64); -} - -#[test] -#[cfg(panic = "unwind")] -fn uninit_fill_from_mid_panic() { - use std::panic; - - struct IterUntilPanic { - limit: usize, - rc: Rc<()>, - } - - impl Iterator for IterUntilPanic { - type Item = Rc<()>; - fn next(&mut self) -> Option { - if Rc::strong_count(&self.rc) >= self.limit { - panic!("expected panic on next"); - } - Some(self.rc.clone()) - } - } - - let rc = Rc::new(()); - - let mut dst = [ - MaybeUninit::uninit(), - MaybeUninit::uninit(), - MaybeUninit::uninit(), - MaybeUninit::uninit(), - ]; - - let src = IterUntilPanic { limit: 3, rc: rc.clone() }; - - let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { - MaybeUninit::fill_from(&mut dst, src); - })); - - match err { - Ok(_) => unreachable!(), - Err(payload) => { - payload - .downcast::<&'static str>() - .and_then(|s| if *s == "expected panic on next" { Ok(s) } else { Err(s) }) - .unwrap_or_else(|p| panic::resume_unwind(p)); - - assert_eq!(Rc::strong_count(&rc), 1) - } - } -} - -#[test] -#[cfg(panic = "unwind")] -fn uninit_fill_from_no_drop() { - let mut dst = [MaybeUninit::uninit()]; - let src = [Bomb]; - - MaybeUninit::fill_from(&mut dst, src.iter()); - - forget(src); -} - -#[test] -fn uninit_const_assume_init_read() { - const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() }; - assert_eq!(FOO, 42); -} - -#[test] -fn const_maybe_uninit() { - use std::ptr; - - #[derive(Debug, PartialEq)] - struct Foo { - x: u8, - y: u8, - } - - const FIELD_BY_FIELD: Foo = unsafe { - let mut val = MaybeUninit::uninit(); - init_y(&mut val); // order shouldn't matter - init_x(&mut val); - val.assume_init() - }; - - const fn init_x(foo: &mut MaybeUninit) { - unsafe { - *ptr::addr_of_mut!((*foo.as_mut_ptr()).x) = 1; - } - } - - const fn init_y(foo: &mut MaybeUninit) { - unsafe { - *ptr::addr_of_mut!((*foo.as_mut_ptr()).y) = 2; - } - } - - assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 }); -} - -#[test] -fn offset_of() { - #[repr(C)] - struct Foo { - x: u8, - y: u16, - z: Bar, - } - - #[repr(C)] - struct Bar(u8, u8); - - assert_eq!(offset_of!(Foo, x), 0); - assert_eq!(offset_of!(Foo, y), 2); - assert_eq!(offset_of!(Foo, z.0), 4); - assert_eq!(offset_of!(Foo, z.1), 5); - - // Layout of tuples is unstable - assert!(offset_of!((u8, u16), 0) <= size_of::<(u8, u16)>() - 1); - assert!(offset_of!((u8, u16), 1) <= size_of::<(u8, u16)>() - 2); - - #[repr(C)] - struct Generic { - x: u8, - y: u32, - z: T, - } - - trait Trait {} - - // Ensure that this type of generics works - fn offs_of_z() -> usize { - offset_of!(Generic, z) - } - - assert_eq!(offset_of!(Generic, z), 8); - assert_eq!(offs_of_z::(), 8); - - // Ensure that it works with the implicit lifetime in `Box`. - assert_eq!(offset_of!(Generic>, z), 8); -} - -#[test] -fn offset_of_union() { - #[repr(C)] - union Foo { - x: u8, - y: u16, - z: Bar, - } - - #[repr(C)] - #[derive(Copy, Clone)] - struct Bar(u8, u8); - - assert_eq!(offset_of!(Foo, x), 0); - assert_eq!(offset_of!(Foo, y), 0); - assert_eq!(offset_of!(Foo, z.0), 0); - assert_eq!(offset_of!(Foo, z.1), 1); -} - -#[test] -fn offset_of_dst() { - #[repr(C)] - struct Alpha { - x: u8, - y: u16, - z: [u8], - } - - trait Trait {} - - #[repr(C)] - struct Beta { - x: u8, - y: u16, - z: dyn Trait, - } - - extern "C" { - type Extern; - } - - #[repr(C)] - struct Gamma { - x: u8, - y: u16, - z: Extern, - } - - assert_eq!(offset_of!(Alpha, x), 0); - assert_eq!(offset_of!(Alpha, y), 2); - - assert_eq!(offset_of!(Beta, x), 0); - assert_eq!(offset_of!(Beta, y), 2); - - assert_eq!(offset_of!(Gamma, x), 0); - assert_eq!(offset_of!(Gamma, y), 2); -} - -#[test] -fn offset_of_packed() { - #[repr(C, packed)] - struct Foo { - x: u8, - y: u16, - } - - assert_eq!(offset_of!(Foo, x), 0); - assert_eq!(offset_of!(Foo, y), 1); -} - -#[test] -fn offset_of_projection() { - #[repr(C)] - struct Foo { - x: u8, - y: u16, - } - - trait Projector { - type Type; - } - - impl Projector for () { - type Type = Foo; - } - - assert_eq!(offset_of!(<() as Projector>::Type, x), 0); - assert_eq!(offset_of!(<() as Projector>::Type, y), 2); -} - -#[test] -fn offset_of_alias() { - #[repr(C)] - struct Foo { - x: u8, - y: u16, - } - - type Bar = Foo; - - assert_eq!(offset_of!(Bar, x), 0); - assert_eq!(offset_of!(Bar, y), 2); -} - -#[test] -fn const_offset_of() { - #[repr(C)] - struct Foo { - x: u8, - y: u16, - } - - const X_OFFSET: usize = offset_of!(Foo, x); - const Y_OFFSET: usize = offset_of!(Foo, y); - - assert_eq!(X_OFFSET, 0); - assert_eq!(Y_OFFSET, 2); -} - -#[test] -fn offset_of_without_const_promotion() { - #[repr(C)] - struct Foo { - x: u8, - y: u16, - _scp: SuppressConstPromotion, - } - - // Normally, offset_of is always const promoted. - // The generic parameter prevents this from happening. - // This is needed to test the codegen impl of offset_of - fn inner() { - assert_eq!(offset_of!(Foo, x), 0); - assert_eq!(offset_of!(Foo, y), 2); - } - - inner::<()>(); -} - -#[test] -fn offset_of_addr() { - #[repr(C)] - struct Foo { - x: u8, - y: u16, - z: Bar, - } - - #[repr(C)] - struct Bar(u8, u8); - - let base = Foo { x: 0, y: 0, z: Bar(0, 0) }; - - assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, x), ptr::addr_of!(base.x).addr()); - assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, y), ptr::addr_of!(base.y).addr()); - assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.0), ptr::addr_of!(base.z.0).addr()); - assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.1), ptr::addr_of!(base.z.1).addr()); -} - -#[test] -fn const_maybe_uninit_zeroed() { - // Sanity check for `MaybeUninit::zeroed` in a realistic const situation (plugin array term) - - // It is crucial that this type has no padding! - #[repr(C)] - struct Foo { - a: Option<&'static u8>, - b: Bar, - c: f32, - _pad: u32, - d: *const u8, - } - - #[repr(C)] - struct Bar(usize); - - struct FooPtr(*const Foo); - unsafe impl Sync for FooPtr {} - - static UNINIT: FooPtr = FooPtr([unsafe { MaybeUninit::zeroed().assume_init() }].as_ptr()); - const SIZE: usize = size_of::(); - - assert_eq!(unsafe { (*UNINIT.0.cast::<[[u8; SIZE]; 1]>())[0] }, [0u8; SIZE]); -} diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs deleted file mode 100644 index f01b43282ec..00000000000 --- a/library/core/tests/net/ip_addr.rs +++ /dev/null @@ -1,1092 +0,0 @@ -use core::net::{ - IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope, SocketAddr, SocketAddrV4, SocketAddrV6, -}; -use core::str::FromStr; - -use super::{sa4, sa6}; - -#[test] -fn test_from_str_ipv4() { - assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); - assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); - assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); - - // out of range - let none: Option = "256.0.0.1".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "255.0.0".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "255.0.0.1.2".parse().ok(); - assert_eq!(None, none); - // no number between dots - let none: Option = "255.0..1".parse().ok(); - assert_eq!(None, none); - // octal - let none: Option = "255.0.0.01".parse().ok(); - assert_eq!(None, none); - // octal zero - let none: Option = "255.0.0.00".parse().ok(); - assert_eq!(None, none); - let none: Option = "255.0.00.0".parse().ok(); - assert_eq!(None, none); -} - -#[test] -fn test_from_str_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse()); - - // too long group - let none: Option = "::00000".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "1:2:3:4:5:6:7".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); - assert_eq!(None, none); - // triple colon - let none: Option = "1:2:::6:7:8".parse().ok(); - assert_eq!(None, none); - // two double colons - let none: Option = "1:2::6::8".parse().ok(); - assert_eq!(None, none); - // `::` indicating zero groups of zeros - let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); - assert_eq!(None, none); -} - -#[test] -fn test_from_str_ipv4_in_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse()); - assert_eq!( - Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), - "64:ff9b::192.0.2.33".parse() - ); - assert_eq!( - Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), - "2001:db8:122:c000:2:2100:192.0.2.33".parse() - ); - - // colon after v4 - let none: Option = "::127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // not enough groups - let none: Option = "1:2:3:4:5:127.0.0.1".parse().ok(); - assert_eq!(None, none); - // too many groups - let none: Option = "1:2:3:4:5:6:7:127.0.0.1".parse().ok(); - assert_eq!(None, none); -} - -#[test] -fn test_from_str_socket_addr() { - assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); - assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); - assert_eq!( - Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), - "[2a02:6b8:0:1::1]:53".parse() - ); - assert_eq!( - Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)), - "[2a02:6b8:0:1::1]:53".parse() - ); - assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse()); - assert_eq!( - Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)), - "[::127.0.0.1]:22".parse() - ); - - // without port - let none: Option = "127.0.0.1".parse().ok(); - assert_eq!(None, none); - // without port - let none: Option = "127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // wrong brackets around v4 - let none: Option = "[127.0.0.1]:22".parse().ok(); - assert_eq!(None, none); - // port out of range - let none: Option = "127.0.0.1:123456".parse().ok(); - assert_eq!(None, none); -} - -#[test] -fn ipv4_addr_to_string() { - assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1"); - // Short address - assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); - // Long address - assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); - - // Test padding - assert_eq!(format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); - assert_eq!(format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); -} - -#[test] -fn ipv6_addr_to_string() { - // ipv4-mapped address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); - - // ipv4-compatible address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::c000:280"); - - // v6 address with no zero segments - assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); - - // longest possible IPv6 length - assert_eq!( - Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(), - "1111:2222:3333:4444:5555:6666:7777:8888" - ); - // padding - assert_eq!(format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 "); - assert_eq!(format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8"); - - // reduce a single run of zeros - assert_eq!( - "ae::ffff:102:304", - Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() - ); - - // don't reduce just a single zero segment - assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); - - // 'any' address - assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // loopback address - assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); - - // ends in zeros - assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // two runs of zeros, second one is longer - assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); - - // two runs of zeros, equal length - assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); - - // don't prefix `0x` to each segment in `dbg!`. - assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8))); -} - -#[test] -fn ipv4_to_ipv6() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() - ); - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() - ); -} - -#[test] -fn ipv6_to_ipv4_mapped() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None); -} - -#[test] -fn ipv6_to_ipv4() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); -} - -#[test] -fn ip_properties() { - macro_rules! ip { - ($s:expr) => { - IpAddr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr) => { - check!($s, 0); - }; - - ($s:expr, $mask:expr) => {{ - let unspec: u8 = 1 << 0; - let loopback: u8 = 1 << 1; - let global: u8 = 1 << 2; - let multicast: u8 = 1 << 3; - let doc: u8 = 1 << 4; - let benchmarking: u8 = 1 << 5; - - if ($mask & unspec) == unspec { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - - if ($mask & multicast) == multicast { - assert!(ip!($s).is_multicast()); - } else { - assert!(!ip!($s).is_multicast()); - } - - if ($mask & doc) == doc { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - - if ($mask & benchmarking) == benchmarking { - assert!(ip!($s).is_benchmarking()); - } else { - assert!(!ip!($s).is_benchmarking()); - } - }}; - } - - let unspec: u8 = 1 << 0; - let loopback: u8 = 1 << 1; - let global: u8 = 1 << 2; - let multicast: u8 = 1 << 3; - let doc: u8 = 1 << 4; - let benchmarking: u8 = 1 << 5; - - check!("0.0.0.0", unspec); - check!("0.0.0.1"); - check!("0.1.0.0"); - check!("10.9.8.7"); - check!("127.1.2.3", loopback); - check!("172.31.254.253"); - check!("169.254.253.242"); - check!("192.0.2.183", doc); - check!("192.1.2.183", global); - check!("192.168.254.253"); - check!("198.51.100.0", doc); - check!("203.0.113.0", doc); - check!("203.2.113.0", global); - check!("224.0.0.0", global | multicast); - check!("239.255.255.255", global | multicast); - check!("255.255.255.255"); - // make sure benchmarking addresses are not global - check!("198.18.0.0", benchmarking); - check!("198.18.54.2", benchmarking); - check!("198.19.255.255", benchmarking); - // make sure addresses reserved for protocol assignment are not global - check!("192.0.0.0"); - check!("192.0.0.255"); - check!("192.0.0.100"); - // make sure reserved addresses are not global - check!("240.0.0.0"); - check!("251.54.1.76"); - check!("254.255.255.255"); - // make sure shared addresses are not global - check!("100.64.0.0"); - check!("100.127.255.255"); - check!("100.100.100.0"); - - check!("::", unspec); - check!("::1", loopback); - check!("::2", global); - check!("1::", global); - check!("fc00::"); - check!("fdff:ffff::"); - check!("fe80:ffff::"); - check!("febf:ffff::"); - check!("fec0::", global); - check!("ff01::", global | multicast); - check!("ff02::", global | multicast); - check!("ff03::", global | multicast); - check!("ff04::", global | multicast); - check!("ff05::", global | multicast); - check!("ff08::", global | multicast); - check!("ff0e::", global | multicast); - check!("2001:db8:85a3::8a2e:370:7334", doc); - check!("3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff", doc); - check!("2001:2::ac32:23ff:21", benchmarking); - check!("102:304:506:708:90a:b0c:d0e:f10", global); -} - -#[test] -fn ipv4_properties() { - macro_rules! ip { - ($s:expr) => { - Ipv4Addr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr) => { - check!($s, 0); - }; - - ($s:expr, $mask:expr) => {{ - let unspec: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let private: u16 = 1 << 2; - let link_local: u16 = 1 << 3; - let global: u16 = 1 << 4; - let multicast: u16 = 1 << 5; - let broadcast: u16 = 1 << 6; - let documentation: u16 = 1 << 7; - let benchmarking: u16 = 1 << 8; - let reserved: u16 = 1 << 10; - let shared: u16 = 1 << 11; - - if ($mask & unspec) == unspec { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - - if ($mask & private) == private { - assert!(ip!($s).is_private()); - } else { - assert!(!ip!($s).is_private()); - } - - if ($mask & link_local) == link_local { - assert!(ip!($s).is_link_local()); - } else { - assert!(!ip!($s).is_link_local()); - } - - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - - if ($mask & multicast) == multicast { - assert!(ip!($s).is_multicast()); - } else { - assert!(!ip!($s).is_multicast()); - } - - if ($mask & broadcast) == broadcast { - assert!(ip!($s).is_broadcast()); - } else { - assert!(!ip!($s).is_broadcast()); - } - - if ($mask & documentation) == documentation { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - - if ($mask & benchmarking) == benchmarking { - assert!(ip!($s).is_benchmarking()); - } else { - assert!(!ip!($s).is_benchmarking()); - } - - if ($mask & reserved) == reserved { - assert!(ip!($s).is_reserved()); - } else { - assert!(!ip!($s).is_reserved()); - } - - if ($mask & shared) == shared { - assert!(ip!($s).is_shared()); - } else { - assert!(!ip!($s).is_shared()); - } - }}; - } - - let unspec: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let private: u16 = 1 << 2; - let link_local: u16 = 1 << 3; - let global: u16 = 1 << 4; - let multicast: u16 = 1 << 5; - let broadcast: u16 = 1 << 6; - let documentation: u16 = 1 << 7; - let benchmarking: u16 = 1 << 8; - let reserved: u16 = 1 << 10; - let shared: u16 = 1 << 11; - - check!("0.0.0.0", unspec); - check!("0.0.0.1"); - check!("0.1.0.0"); - check!("10.9.8.7", private); - check!("127.1.2.3", loopback); - check!("172.31.254.253", private); - check!("169.254.253.242", link_local); - check!("192.0.2.183", documentation); - check!("192.1.2.183", global); - check!("192.168.254.253", private); - check!("198.51.100.0", documentation); - check!("203.0.113.0", documentation); - check!("203.2.113.0", global); - check!("224.0.0.0", global | multicast); - check!("239.255.255.255", global | multicast); - check!("255.255.255.255", broadcast); - check!("198.18.0.0", benchmarking); - check!("198.18.54.2", benchmarking); - check!("198.19.255.255", benchmarking); - check!("192.0.0.0"); - check!("192.0.0.8"); - check!("192.0.0.9", global); - check!("192.0.0.10", global); - check!("192.0.0.11"); - check!("192.0.0.255"); - check!("192.0.0.100"); - check!("240.0.0.0", reserved); - check!("251.54.1.76", reserved); - check!("254.255.255.255", reserved); - check!("100.64.0.0", shared); - check!("100.127.255.255", shared); - check!("100.100.100.0", shared); -} - -#[test] -fn ipv6_properties() { - macro_rules! ip { - ($s:expr) => { - Ipv6Addr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr, &[$($octet:expr),*]) => { - check!($s, &[$($octet),*], 0); - }; - - ($s:expr, &[$($octet:expr),*], $mask:expr) => { - assert_eq!($s, ip!($s).to_string()); - let octets = &[$($octet),*]; - assert_eq!(&ip!($s).octets(), octets); - assert_eq!(Ipv6Addr::from(*octets), ip!($s)); - assert_eq!(Ipv6Addr::from_octets(*octets), ip!($s)); - - let unspecified: u32 = 1 << 0; - let loopback: u32 = 1 << 1; - let unique_local: u32 = 1 << 2; - let global: u32 = 1 << 3; - let unicast_link_local: u32 = 1 << 4; - let unicast_global: u32 = 1 << 7; - let documentation: u32 = 1 << 8; - let benchmarking: u32 = 1 << 16; - let multicast_interface_local: u32 = 1 << 9; - let multicast_link_local: u32 = 1 << 10; - let multicast_realm_local: u32 = 1 << 11; - let multicast_admin_local: u32 = 1 << 12; - let multicast_site_local: u32 = 1 << 13; - let multicast_organization_local: u32 = 1 << 14; - let multicast_global: u32 = 1 << 15; - let multicast: u32 = multicast_interface_local - | multicast_admin_local - | multicast_global - | multicast_link_local - | multicast_realm_local - | multicast_site_local - | multicast_organization_local; - let ipv4_mapped: u32 = 1 << 17; - - if ($mask & unspecified) == unspecified { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - if ($mask & unique_local) == unique_local { - assert!(ip!($s).is_unique_local()); - } else { - assert!(!ip!($s).is_unique_local()); - } - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - if ($mask & unicast_link_local) == unicast_link_local { - assert!(ip!($s).is_unicast_link_local()); - } else { - assert!(!ip!($s).is_unicast_link_local()); - } - if ($mask & unicast_global) == unicast_global { - assert!(ip!($s).is_unicast_global()); - } else { - assert!(!ip!($s).is_unicast_global()); - } - if ($mask & documentation) == documentation { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - if ($mask & benchmarking) == benchmarking { - assert!(ip!($s).is_benchmarking()); - } else { - assert!(!ip!($s).is_benchmarking()); - } - if ($mask & multicast) != 0 { - assert!(ip!($s).multicast_scope().is_some()); - assert!(ip!($s).is_multicast()); - } else { - assert!(ip!($s).multicast_scope().is_none()); - assert!(!ip!($s).is_multicast()); - } - if ($mask & multicast_interface_local) == multicast_interface_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::InterfaceLocal); - } - if ($mask & multicast_link_local) == multicast_link_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::LinkLocal); - } - if ($mask & multicast_realm_local) == multicast_realm_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::RealmLocal); - } - if ($mask & multicast_admin_local) == multicast_admin_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::AdminLocal); - } - if ($mask & multicast_site_local) == multicast_site_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::SiteLocal); - } - if ($mask & multicast_organization_local) == multicast_organization_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::OrganizationLocal); - } - if ($mask & multicast_global) == multicast_global { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::Global); - } - if ($mask & ipv4_mapped) == ipv4_mapped { - assert!(ip!($s).is_ipv4_mapped()); - } else { - assert!(!ip!($s).is_ipv4_mapped()); - } - } - } - - let unspecified: u32 = 1 << 0; - let loopback: u32 = 1 << 1; - let unique_local: u32 = 1 << 2; - let global: u32 = 1 << 3; - let unicast_link_local: u32 = 1 << 4; - let unicast_global: u32 = 1 << 7; - let documentation: u32 = 1 << 8; - let benchmarking: u32 = 1 << 16; - let multicast_interface_local: u32 = 1 << 9; - let multicast_link_local: u32 = 1 << 10; - let multicast_realm_local: u32 = 1 << 11; - let multicast_admin_local: u32 = 1 << 12; - let multicast_site_local: u32 = 1 << 13; - let multicast_organization_local: u32 = 1 << 14; - let multicast_global: u32 = 1 << 15; - let ipv4_mapped: u32 = 1 << 17; - - check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); - - check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); - - check!("::2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); - - check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); - - check!( - "::ffff:127.0.0.1", - &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1], - unicast_global | ipv4_mapped - ); - - check!( - "64:ff9b:1::", - &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_global - ); - - check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); - - check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); - - check!( - "2001:1::1", - &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], - global | unicast_global - ); - - check!( - "2001:1::2", - &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], - global | unicast_global - ); - - check!( - "2001:3::", - &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - global | unicast_global - ); - - check!( - "2001:4:112::", - &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - global | unicast_global - ); - - check!( - "2001:20::", - &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - global | unicast_global - ); - check!( - "2001:30::", - &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - global | unicast_global - ); - check!("2001:40::", &[0x20, 1, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); - - check!( - "2001:200::", - &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - global | unicast_global - ); - - check!("2002::", &[0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); - - check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); - - check!( - "fdff:ffff::", - &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unique_local - ); - - check!( - "fe80:ffff::", - &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); - - check!( - "febf:ffff::", - &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); - - check!( - "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", - &[ - 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ], - unicast_link_local - ); - - check!( - "fe80::ffff:ffff:ffff:ffff", - &[ - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ], - unicast_link_local - ); - - check!( - "fe80:0:0:1::", - &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "fec0::", - &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_global | global - ); - - check!( - "ff01::", - &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_interface_local | global - ); - - check!( - "ff02::", - &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_link_local | global - ); - - check!( - "ff03::", - &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_realm_local | global - ); - - check!( - "ff04::", - &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_admin_local | global - ); - - check!( - "ff05::", - &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_site_local | global - ); - - check!( - "ff08::", - &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_organization_local | global - ); - - check!( - "ff0e::", - &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_global | global - ); - - check!( - "2001:db8:85a3::8a2e:370:7334", - &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], - documentation - ); - - check!( - "3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff", - &[ - 0x3f, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ], - documentation - ); - - check!( - "2001:2::ac32:23ff:21", - &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21], - benchmarking - ); - - check!( - "102:304:506:708:90a:b0c:d0e:f10", - &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], - global | unicast_global - ); -} - -#[test] -fn test_ipv4_to_int() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(u32::from(a), 0x11223344); -} - -#[test] -fn test_int_to_ipv4() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(Ipv4Addr::from(0x11223344), a); -} - -#[test] -fn test_ipv6_to_int() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); -} - -#[test] -fn test_int_to_ipv6() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); -} - -#[test] -fn ipv4_from_constructors() { - assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); - assert!(Ipv4Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); - assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); - assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); - assert!(Ipv4Addr::BROADCAST.is_broadcast()); -} - -#[test] -fn ipv6_from_constructors() { - assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - assert!(Ipv6Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); -} - -#[test] -fn ipv4_from_octets() { - assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)); - assert_eq!(Ipv4Addr::from_octets([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)); -} - -#[test] -fn ipv6_from_segments() { - let from_u16s = - Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let from_u16s_explicit = - Ipv6Addr::from_segments([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); - assert_eq!(new, from_u16s); - assert_eq!(new, from_u16s_explicit); -} - -#[test] -fn ipv6_from_octets() { - let from_u16s = - Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let from_u8s = Ipv6Addr::from([ - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, - 0xff, - ]); - let from_u16s_explicit = - Ipv6Addr::from_segments([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let from_u8s_explicit = Ipv6Addr::from_octets([ - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, - 0xff, - ]); - assert_eq!(from_u16s, from_u8s); - assert_eq!(from_u16s, from_u16s_explicit); - assert_eq!(from_u16s_explicit, from_u8s_explicit); -} - -#[test] -fn cmp() { - let v41 = Ipv4Addr::new(100, 64, 3, 3); - let v42 = Ipv4Addr::new(192, 0, 2, 2); - let v61 = "2001:db8:f00::1002".parse::().unwrap(); - let v62 = "2001:db8:f00::2001".parse::().unwrap(); - assert!(v41 < v42); - assert!(v61 < v62); - - assert_eq!(v41, IpAddr::V4(v41)); - assert_eq!(v61, IpAddr::V6(v61)); - assert!(v41 != IpAddr::V4(v42)); - assert!(v61 != IpAddr::V6(v62)); - - assert!(v41 < IpAddr::V4(v42)); - assert!(v61 < IpAddr::V6(v62)); - assert!(IpAddr::V4(v41) < v42); - assert!(IpAddr::V6(v61) < v62); - - assert!(v41 < IpAddr::V6(v61)); - assert!(IpAddr::V4(v41) < v61); -} - -#[test] -fn is_v4() { - let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); - assert!(ip.is_ipv4()); - assert!(!ip.is_ipv6()); -} - -#[test] -fn is_v6() { - let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); - assert!(!ip.is_ipv4()); - assert!(ip.is_ipv6()); -} - -#[test] -fn ipv4_const() { - // test that the methods of `Ipv4Addr` are usable in a const context - - const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); - - const OCTETS: [u8; 4] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [127, 0, 0, 1]); - - const FROM_OCTETS: Ipv4Addr = Ipv4Addr::from_octets(OCTETS); - assert_eq!(IP_ADDRESS, FROM_OCTETS); - - const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_PRIVATE: bool = IP_ADDRESS.is_private(); - assert!(!IS_PRIVATE); - - const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local(); - assert!(!IS_LINK_LOCAL); - - const IS_GLOBAL: bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_SHARED: bool = IP_ADDRESS.is_shared(); - assert!(!IS_SHARED); - - const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); - assert!(!IS_BENCHMARKING); - - const IS_RESERVED: bool = IP_ADDRESS.is_reserved(); - assert!(!IS_RESERVED); - - const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast(); - assert!(!IS_BROADCAST); - - const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); - assert_eq!( - IP_V6_COMPATIBLE, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1]) - ); - - const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); - assert_eq!( - IP_V6_MAPPED, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1]) - ); -} - -#[test] -fn ipv6_const() { - // test that the methods of `Ipv6Addr` are usable in a const context - - const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); - - const SEGMENTS: [u16; 8] = IP_ADDRESS.segments(); - assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]); - - const FROM_SEGMENTS: Ipv6Addr = Ipv6Addr::from_segments(SEGMENTS); - assert_eq!(IP_ADDRESS, FROM_SEGMENTS); - - const OCTETS: [u8; 16] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); - - const FROM_OCTETS: Ipv6Addr = Ipv6Addr::from_octets(OCTETS); - assert_eq!(IP_ADDRESS, FROM_OCTETS); - - const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_GLOBAL: bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local(); - assert!(!IS_UNIQUE_LOCAL); - - const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); - assert!(!IS_UNICAST_LINK_LOCAL); - - const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); - assert!(!IS_BENCHMARKING); - - const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global(); - assert!(!IS_UNICAST_GLOBAL); - - const MULTICAST_SCOPE: Option = IP_ADDRESS.multicast_scope(); - assert_eq!(MULTICAST_SCOPE, None); - - const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IS_IPV4_MAPPED: bool = IP_ADDRESS.is_ipv4_mapped(); - assert!(!IS_IPV4_MAPPED); - - const IP_V4: Option = IP_ADDRESS.to_ipv4(); - assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); -} - -#[test] -fn ip_const() { - // test that the methods of `IpAddr` are usable in a const context - - const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); - - const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_GLOBAL: bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IS_IP_V4: bool = IP_ADDRESS.is_ipv4(); - assert!(IS_IP_V4); - - const IS_IP_V6: bool = IP_ADDRESS.is_ipv6(); - assert!(!IS_IP_V6); -} - -#[test] -fn structural_match() { - // test that all IP types can be structurally matched upon - - const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST; - match IPV4 { - Ipv4Addr::LOCALHOST => {} - _ => unreachable!(), - } - - const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST; - match IPV6 { - Ipv6Addr::LOCALHOST => {} - _ => unreachable!(), - } - - const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); - match IP { - IpAddr::V4(Ipv4Addr::LOCALHOST) => {} - _ => unreachable!(), - } -} diff --git a/library/core/tests/net/mod.rs b/library/core/tests/net/mod.rs deleted file mode 100644 index 8f17bbe5548..00000000000 --- a/library/core/tests/net/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -use core::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; - -mod ip_addr; -mod parser; -mod socket_addr; - -pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr { - SocketAddr::V4(SocketAddrV4::new(a, p)) -} - -pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr { - SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0)) -} diff --git a/library/core/tests/net/parser.rs b/library/core/tests/net/parser.rs deleted file mode 100644 index e03959ac77c..00000000000 --- a/library/core/tests/net/parser.rs +++ /dev/null @@ -1,150 +0,0 @@ -// FIXME: These tests are all excellent candidates for AFL fuzz testing - -use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; -use core::str::FromStr; - -const PORT: u16 = 8080; -const SCOPE_ID: u32 = 1337; - -const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1); -const IPV4_STR: &str = "192.168.0.1"; -const IPV4_STR_PORT: &str = "192.168.0.1:8080"; -const IPV4_STR_WITH_OCTAL: &str = "0127.0.0.1"; -const IPV4_STR_WITH_HEX: &str = "0x10.0.0.1"; - -const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1); -const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; -const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; -const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; -const IPV6_STR_V4_WITH_OCTAL: &str = "2001:db8::0127.0.0.1"; -const IPV6_STR_V4_WITH_HEX: &str = "2001:db8::0x10.0.0.1"; -const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; -const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080"; - -#[test] -fn parse_ipv4() { - let result: Ipv4Addr = IPV4_STR.parse().unwrap(); - assert_eq!(result, IPV4); - - assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err()); - assert!(Ipv4Addr::from_str(IPV4_STR_WITH_OCTAL).is_err()); - assert!(Ipv4Addr::from_str(IPV4_STR_WITH_HEX).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err()); -} - -#[test] -fn parse_ipv6() { - let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap(); - assert_eq!(result, IPV6); - - let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap(); - assert_eq!(result, IPV6); - - let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap(); - assert_eq!(result, IPV6); - - assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_OCTAL).is_err()); - assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_HEX).is_err()); - assert!(Ipv6Addr::from_str(IPV4_STR).is_err()); - assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err()); - assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err()); -} - -#[test] -fn parse_ip() { - let result: IpAddr = IPV4_STR.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV4)); - - let result: IpAddr = IPV6_STR_FULL.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV6)); - - let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV6)); - - let result: IpAddr = IPV6_STR_V4.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV6)); - - assert!(IpAddr::from_str(IPV4_STR_PORT).is_err()); - assert!(IpAddr::from_str(IPV6_STR_PORT).is_err()); -} - -#[test] -fn parse_socket_v4() { - let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddrV4::new(IPV4, PORT)); - - assert!(SocketAddrV4::from_str(IPV4_STR).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err()); -} - -#[test] -fn parse_socket_v6() { - assert_eq!(IPV6_STR_PORT.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, 0))); - assert_eq!(IPV6_STR_PORT_SCOPE_ID.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, SCOPE_ID))); - - assert!(SocketAddrV6::from_str(IPV4_STR).is_err()); - assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err()); - assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err()); - assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err()); -} - -#[test] -fn parse_socket() { - let result: SocketAddr = IPV4_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddr::from((IPV4, PORT))); - - let result: SocketAddr = IPV6_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddr::from((IPV6, PORT))); - - assert!(SocketAddr::from_str(IPV4_STR).is_err()); - assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err()); - assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(SocketAddr::from_str(IPV6_STR_V4).is_err()); -} - -#[test] -fn ipv6_corner_cases() { - let result: Ipv6Addr = "1::".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0)); - - let result: Ipv6Addr = "1:1::".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0)); - - let result: Ipv6Addr = "::1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - - let result: Ipv6Addr = "::1:1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1)); - - let result: Ipv6Addr = "::".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - - let result: Ipv6Addr = "::192.168.0.1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1)); - - let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1)); - - let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1)); -} - -// Things that might not seem like failures but are -#[test] -fn ipv6_corner_failures() { - // No IP address before the :: - assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err()); - - // :: must have at least 1 set of zeroes - assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err()); - - // Need brackets for a port - assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err()); -} diff --git a/library/core/tests/net/socket_addr.rs b/library/core/tests/net/socket_addr.rs deleted file mode 100644 index 3d013d37e04..00000000000 --- a/library/core/tests/net/socket_addr.rs +++ /dev/null @@ -1,244 +0,0 @@ -use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; - -#[test] -fn ipv4_socket_addr_to_string() { - // Shortest possible IPv4 length. - assert_eq!(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0).to_string(), "0.0.0.0:0"); - - // Longest possible IPv4 length. - assert_eq!( - SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), u16::MAX).to_string(), - "255.255.255.255:65535" - ); - - // Test padding. - assert_eq!( - &format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), - "1.1.1.1:53 " - ); - assert_eq!( - &format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), - " 1.1.1.1:53" - ); -} - -#[test] -fn ipv6_socket_addr_to_string() { - // IPv4-mapped address. - assert_eq!( - SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280), 8080, 0, 0) - .to_string(), - "[::ffff:192.0.2.128]:8080" - ); - - // IPv4-compatible address. - assert_eq!( - SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), - "[::c000:280]:8080" - ); - - // IPv6 address with no zero segments. - assert_eq!( - SocketAddrV6::new(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15), 80, 0, 0).to_string(), - "[8:9:a:b:c:d:e:f]:80" - ); - - // Shortest possible IPv6 length. - assert_eq!(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0).to_string(), "[::]:0"); - - // Longest possible IPv6 length. - assert_eq!( - SocketAddrV6::new( - Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888), - u16::MAX, - u32::MAX, - u32::MAX, - ) - .to_string(), - "[1111:2222:3333:4444:5555:6666:7777:8888%4294967295]:65535" - ); - - // Test padding. - assert_eq!( - &format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), - "[1:2:3:4:5:6:7:8]:9 " - ); - assert_eq!( - &format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), - " [1:2:3:4:5:6:7:8]:9" - ); -} - -#[test] -fn set_ip() { - fn ip4(low: u8) -> Ipv4Addr { - Ipv4Addr::new(77, 88, 21, low) - } - fn ip6(low: u16) -> Ipv6Addr { - Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) - } - - let mut v4 = SocketAddrV4::new(ip4(11), 80); - assert_eq!(v4.ip(), &ip4(11)); - v4.set_ip(ip4(12)); - assert_eq!(v4.ip(), &ip4(12)); - - let mut addr = SocketAddr::V4(v4); - assert_eq!(addr.ip(), IpAddr::V4(ip4(12))); - addr.set_ip(IpAddr::V4(ip4(13))); - assert_eq!(addr.ip(), IpAddr::V4(ip4(13))); - addr.set_ip(IpAddr::V6(ip6(14))); - assert_eq!(addr.ip(), IpAddr::V6(ip6(14))); - - let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0); - assert_eq!(v6.ip(), &ip6(1)); - v6.set_ip(ip6(2)); - assert_eq!(v6.ip(), &ip6(2)); - - let mut addr = SocketAddr::V6(v6); - assert_eq!(addr.ip(), IpAddr::V6(ip6(2))); - addr.set_ip(IpAddr::V6(ip6(3))); - assert_eq!(addr.ip(), IpAddr::V6(ip6(3))); - addr.set_ip(IpAddr::V4(ip4(4))); - assert_eq!(addr.ip(), IpAddr::V4(ip4(4))); -} - -#[test] -fn set_port() { - let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80); - assert_eq!(v4.port(), 80); - v4.set_port(443); - assert_eq!(v4.port(), 443); - - let mut addr = SocketAddr::V4(v4); - assert_eq!(addr.port(), 443); - addr.set_port(8080); - assert_eq!(addr.port(), 8080); - - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0); - assert_eq!(v6.port(), 80); - v6.set_port(443); - assert_eq!(v6.port(), 443); - - let mut addr = SocketAddr::V6(v6); - assert_eq!(addr.port(), 443); - addr.set_port(8080); - assert_eq!(addr.port(), 8080); -} - -#[test] -fn set_flowinfo() { - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0); - assert_eq!(v6.flowinfo(), 10); - v6.set_flowinfo(20); - assert_eq!(v6.flowinfo(), 20); -} - -#[test] -fn set_scope_id() { - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10); - assert_eq!(v6.scope_id(), 10); - v6.set_scope_id(20); - assert_eq!(v6.scope_id(), 20); -} - -#[test] -fn is_v4() { - let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); - assert!(v4.is_ipv4()); - assert!(!v4.is_ipv6()); -} - -#[test] -fn is_v6() { - let v6 = SocketAddr::V6(SocketAddrV6::new( - Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), - 80, - 10, - 0, - )); - assert!(!v6.is_ipv4()); - assert!(v6.is_ipv6()); -} - -#[test] -fn socket_v4_to_str() { - let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080); - - assert_eq!(format!("{socket}"), "192.168.0.1:8080"); - assert_eq!(format!("{socket:<20}"), "192.168.0.1:8080 "); - assert_eq!(format!("{socket:>20}"), " 192.168.0.1:8080"); - assert_eq!(format!("{socket:^20}"), " 192.168.0.1:8080 "); - assert_eq!(format!("{socket:.10}"), "192.168.0."); -} - -#[test] -fn socket_v6_to_str() { - let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0); - - assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{socket:.15}"), "[2a02:6b8:0:1::"); - - socket.set_scope_id(5); - - assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1%5]:53"); - assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1%5]:53 "); - assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1%5]:53"); - assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1%5]:53 "); - assert_eq!(format!("{socket:.18}"), "[2a02:6b8:0:1::1%5"); -} - -#[test] -fn compare() { - let v4_1 = "224.120.45.1:23456".parse::().unwrap(); - let v4_2 = "224.210.103.5:12345".parse::().unwrap(); - let v4_3 = "224.210.103.5:23456".parse::().unwrap(); - let v6_1 = "[2001:db8:f00::1002]:23456".parse::().unwrap(); - let v6_2 = "[2001:db8:f00::2001]:12345".parse::().unwrap(); - let v6_3 = "[2001:db8:f00::2001]:23456".parse::().unwrap(); - let v6_4 = "[2001:db8:f00::2001%42]:23456".parse::().unwrap(); - let mut v6_5 = "[2001:db8:f00::2001]:23456".parse::().unwrap(); - v6_5.set_flowinfo(17); - - // equality - assert_eq!(v4_1, v4_1); - assert_eq!(v6_1, v6_1); - assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1)); - assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); - assert!(v4_1 != v4_2); - assert!(v6_1 != v6_2); - assert!(v6_3 != v6_4); - assert!(v6_3 != v6_5); - - // compare different addresses - assert!(v4_1 < v4_2); - assert!(v6_1 < v6_2); - assert!(v4_2 > v4_1); - assert!(v6_2 > v6_1); - - // compare the same address with different ports - assert!(v4_2 < v4_3); - assert!(v6_2 < v6_3); - assert!(v4_3 > v4_2); - assert!(v6_3 > v6_2); - - // compare different addresses with the same port - assert!(v4_1 < v4_3); - assert!(v6_1 < v6_3); - assert!(v4_3 > v4_1); - assert!(v6_3 > v6_1); - - // compare the same address with different scope_id - assert!(v6_3 < v6_4); - - // compare the same address with different flowinfo - assert!(v6_3 < v6_5); - - // compare with an inferred right-hand side - assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap()); - assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap()); - assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap()); -} diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs deleted file mode 100644 index 43c279053d8..00000000000 --- a/library/core/tests/nonzero.rs +++ /dev/null @@ -1,367 +0,0 @@ -use core::num::{IntErrorKind, NonZero}; -use core::option::Option::None; -use std::mem::size_of; - -#[test] -fn test_create_nonzero_instance() { - let _a = unsafe { NonZero::new_unchecked(21) }; -} - -#[test] -fn test_size_nonzero_in_option() { - assert_eq!(size_of::>(), size_of::>>()); - assert_eq!(size_of::>(), size_of::>>()); -} - -#[test] -fn test_match_on_nonzero_option() { - let a = Some(unsafe { NonZero::::new_unchecked(42) }); - match a { - Some(val) => assert_eq!(val.get(), 42), - None => panic!("unexpected None while matching on Some(NonZero(_))"), - } - - match unsafe { Some(NonZero::::new_unchecked(43)) } { - Some(val) => assert_eq!(val.get(), 43), - None => panic!("unexpected None while matching on Some(NonZero(_))"), - } -} - -#[test] -fn test_match_option_empty_vec() { - let a: Option> = Some(vec![]); - match a { - None => panic!("unexpected None while matching on Some(vec![])"), - _ => {} - } -} - -#[test] -fn test_match_option_vec() { - let a = Some(vec![1, 2, 3, 4]); - match a { - Some(v) => assert_eq!(v, [1, 2, 3, 4]), - None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])"), - } -} - -#[test] -fn test_match_option_rc() { - use std::rc::Rc; - - let five = Rc::new(5); - match Some(five) { - Some(r) => assert_eq!(*r, 5), - None => panic!("unexpected None while matching on Some(Rc::new(5))"), - } -} - -#[test] -fn test_match_option_arc() { - use std::sync::Arc; - - let five = Arc::new(5); - match Some(five) { - Some(a) => assert_eq!(*a, 5), - None => panic!("unexpected None while matching on Some(Arc::new(5))"), - } -} - -#[test] -fn test_match_option_empty_string() { - let a = Some(String::new()); - match a { - None => panic!("unexpected None while matching on Some(String::new())"), - _ => {} - } -} - -#[test] -fn test_match_option_string() { - let five = "Five".to_string(); - match Some(five) { - Some(s) => assert_eq!(s, "Five"), - None => panic!("{}", "unexpected None while matching on Some(String { ... })"), - } -} - -mod atom { - use core::num::NonZero; - - #[derive(PartialEq, Eq)] - pub struct Atom { - index: NonZero, // private - } - - pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZero::new_unchecked(7) } }; -} - -macro_rules! atom { - ("foo") => { - atom::FOO_ATOM - }; -} - -#[test] -fn test_match_nonzero_const_pattern() { - match atom!("foo") { - // Using as a pattern is supported by the compiler: - atom!("foo") => {} - _ => panic!("Expected the const item as a pattern to match."), - } -} - -#[test] -fn test_from_nonzero() { - let nz = NonZero::new(1).unwrap(); - let num: u32 = nz.into(); - assert_eq!(num, 1u32); -} - -#[test] -fn test_from_signed_nonzero() { - let nz = NonZero::new(1).unwrap(); - let num: i32 = nz.into(); - assert_eq!(num, 1i32); -} - -#[test] -fn test_from_str() { - assert_eq!("123".parse::>(), Ok(NonZero::new(123).unwrap())); - assert_eq!( - "0".parse::>().err().map(|e| e.kind().clone()), - Some(IntErrorKind::Zero) - ); - assert_eq!( - "-1".parse::>().err().map(|e| e.kind().clone()), - Some(IntErrorKind::InvalidDigit) - ); - assert_eq!( - "-129".parse::>().err().map(|e| e.kind().clone()), - Some(IntErrorKind::NegOverflow) - ); - assert_eq!( - "257".parse::>().err().map(|e| e.kind().clone()), - Some(IntErrorKind::PosOverflow) - ); -} - -#[test] -fn test_nonzero_bitor() { - let nz_alt = NonZero::new(0b1010_1010).unwrap(); - let nz_low = NonZero::new(0b0000_1111).unwrap(); - - let both_nz: NonZero = nz_alt | nz_low; - assert_eq!(both_nz.get(), 0b1010_1111); - - let rhs_int: NonZero = nz_low | 0b1100_0000u8; - assert_eq!(rhs_int.get(), 0b1100_1111); - - let rhs_zero: NonZero = nz_alt | 0u8; - assert_eq!(rhs_zero.get(), 0b1010_1010); - - let lhs_int: NonZero = 0b0110_0110u8 | nz_alt; - assert_eq!(lhs_int.get(), 0b1110_1110); - - let lhs_zero: NonZero = 0u8 | nz_low; - assert_eq!(lhs_zero.get(), 0b0000_1111); -} - -#[test] -fn test_nonzero_bitor_assign() { - let mut target = NonZero::::new(0b1010_1010).unwrap(); - - target |= NonZero::new(0b0000_1111).unwrap(); - assert_eq!(target.get(), 0b1010_1111); - - target |= 0b0001_0000; - assert_eq!(target.get(), 0b1011_1111); - - target |= 0; - assert_eq!(target.get(), 0b1011_1111); -} - -#[test] -fn test_nonzero_from_int_on_success() { - assert_eq!(NonZero::::try_from(5), Ok(NonZero::new(5).unwrap())); - assert_eq!(NonZero::::try_from(5), Ok(NonZero::new(5).unwrap())); - - assert_eq!(NonZero::::try_from(-5), Ok(NonZero::new(-5).unwrap())); - assert_eq!(NonZero::::try_from(-5), Ok(NonZero::new(-5).unwrap())); -} - -#[test] -fn test_nonzero_from_int_on_err() { - assert!(NonZero::::try_from(0).is_err()); - assert!(NonZero::::try_from(0).is_err()); - - assert!(NonZero::::try_from(0).is_err()); - assert!(NonZero::::try_from(0).is_err()); -} - -#[test] -fn nonzero_const() { - // test that the methods of `NonZeroX>` are usable in a const context - // Note: only tests NonZero - - const NONZERO_U8: NonZero = unsafe { NonZero::new_unchecked(5) }; - - const GET: u8 = NONZERO_U8.get(); - assert_eq!(GET, 5); - - const ZERO: Option> = NonZero::new(0); - assert!(ZERO.is_none()); - - const ONE: Option> = NonZero::new(1); - assert!(ONE.is_some()); - - /* FIXME(#110395) - const FROM_NONZERO_U8: u8 = u8::from(NONZERO_U8); - assert_eq!(FROM_NONZERO_U8, 5); - - const NONZERO_CONVERT: NonZero = NonZero::::from(NONZERO_U8); - assert_eq!(NONZERO_CONVERT.get(), 5); - */ -} - -#[test] -fn nonzero_leading_zeros() { - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 7); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 7); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 15); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 15); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 31); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 31); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 63); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 63); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 127); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 127); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), usize::BITS - 1); - assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), usize::BITS - 1); - - assert_eq!(NonZero::::new(u8::MAX >> 2).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new(u16::MAX >> 2).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new(u32::MAX >> 2).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new(u64::MAX >> 2).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new(u128::MAX >> 2).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new(usize::MAX >> 2).unwrap().leading_zeros(), 2); - assert_eq!(NonZero::::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2); - - assert_eq!(NonZero::::new(u8::MAX).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(-1i8).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(u16::MAX).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(-1i16).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(u32::MAX).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(-1i32).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(u64::MAX).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(-1i64).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(u128::MAX).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(-1i128).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(usize::MAX).unwrap().leading_zeros(), 0); - assert_eq!(NonZero::::new(-1isize).unwrap().leading_zeros(), 0); - - const LEADING_ZEROS: u32 = NonZero::::new(1).unwrap().leading_zeros(); - assert_eq!(LEADING_ZEROS, 15); -} - -#[test] -fn nonzero_trailing_zeros() { - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); - - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); - - assert_eq!(NonZero::::new(1 << 7).unwrap().trailing_zeros(), 7); - assert_eq!(NonZero::::new(1 << 7).unwrap().trailing_zeros(), 7); - assert_eq!(NonZero::::new(1 << 15).unwrap().trailing_zeros(), 15); - assert_eq!(NonZero::::new(1 << 15).unwrap().trailing_zeros(), 15); - assert_eq!(NonZero::::new(1 << 31).unwrap().trailing_zeros(), 31); - assert_eq!(NonZero::::new(1 << 31).unwrap().trailing_zeros(), 31); - assert_eq!(NonZero::::new(1 << 63).unwrap().trailing_zeros(), 63); - assert_eq!(NonZero::::new(1 << 63).unwrap().trailing_zeros(), 63); - assert_eq!(NonZero::::new(1 << 127).unwrap().trailing_zeros(), 127); - assert_eq!(NonZero::::new(1 << 127).unwrap().trailing_zeros(), 127); - - assert_eq!( - NonZero::::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(), - usize::BITS - 1 - ); - assert_eq!( - NonZero::::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(), - usize::BITS - 1 - ); - - const TRAILING_ZEROS: u32 = NonZero::::new(1 << 2).unwrap().trailing_zeros(); - assert_eq!(TRAILING_ZEROS, 2); -} - -#[test] -fn test_nonzero_uint_div() { - let nz = NonZero::new(1).unwrap(); - - let x: u32 = 42u32 / nz; - assert_eq!(x, 42u32); -} - -#[test] -fn test_nonzero_uint_rem() { - let nz = NonZero::new(10).unwrap(); - - let x: u32 = 42u32 % nz; - assert_eq!(x, 2u32); -} - -#[test] -fn test_signed_nonzero_neg() { - assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); - assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); - - assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); - assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); - - assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); - assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); - - assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); - assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); - - assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); - assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); -} - -#[test] -fn test_nonzero_fmt() { - let i = format!("{0}, {0:?}, {0:x}, {0:X}, {0:#x}, {0:#X}, {0:o}, {0:b}, {0:e}, {0:E}", 42); - let nz = format!( - "{0}, {0:?}, {0:x}, {0:X}, {0:#x}, {0:#X}, {0:o}, {0:b}, {0:e}, {0:E}", - NonZero::new(42).unwrap() - ); - - assert_eq!(i, nz); -} diff --git a/library/core/tests/num/bignum.rs b/library/core/tests/num/bignum.rs deleted file mode 100644 index f213fd5366c..00000000000 --- a/library/core/tests/num/bignum.rs +++ /dev/null @@ -1,276 +0,0 @@ -use core::num::bignum::Big32x40; -use core::num::bignum::tests::Big8x3 as Big; - -#[test] -#[should_panic] -fn test_from_u64_overflow() { - Big::from_u64(0x1000000); -} - -#[test] -fn test_add() { - assert_eq!(*Big::from_small(3).add(&Big::from_small(4)), Big::from_small(7)); - assert_eq!(*Big::from_small(3).add(&Big::from_small(0)), Big::from_small(3)); - assert_eq!(*Big::from_small(0).add(&Big::from_small(3)), Big::from_small(3)); - assert_eq!(*Big::from_small(3).add(&Big::from_u64(0xfffe)), Big::from_u64(0x10001)); - assert_eq!(*Big::from_u64(0xfedc).add(&Big::from_u64(0x789)), Big::from_u64(0x10665)); - assert_eq!(*Big::from_u64(0x789).add(&Big::from_u64(0xfedc)), Big::from_u64(0x10665)); -} - -#[test] -#[should_panic] -fn test_add_overflow_1() { - Big::from_small(1).add(&Big::from_u64(0xffffff)); -} - -#[test] -#[should_panic] -fn test_add_overflow_2() { - Big::from_u64(0xffffff).add(&Big::from_small(1)); -} - -#[test] -fn test_add_small() { - assert_eq!(*Big::from_small(3).add_small(4), Big::from_small(7)); - assert_eq!(*Big::from_small(3).add_small(0), Big::from_small(3)); - assert_eq!(*Big::from_small(0).add_small(3), Big::from_small(3)); - assert_eq!(*Big::from_small(7).add_small(250), Big::from_u64(257)); - assert_eq!(*Big::from_u64(0x7fff).add_small(1), Big::from_u64(0x8000)); - assert_eq!(*Big::from_u64(0x2ffe).add_small(0x35), Big::from_u64(0x3033)); - assert_eq!(*Big::from_small(0xdc).add_small(0x89), Big::from_u64(0x165)); -} - -#[test] -#[should_panic] -fn test_add_small_overflow() { - Big::from_u64(0xffffff).add_small(1); -} - -#[test] -fn test_sub() { - assert_eq!(*Big::from_small(7).sub(&Big::from_small(4)), Big::from_small(3)); - assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x789)), Big::from_u64(0xfedc)); - assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0xfedc)), Big::from_u64(0x789)); - assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10664)), Big::from_small(1)); - assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10665)), Big::from_small(0)); -} - -#[test] -#[should_panic] -fn test_sub_underflow_1() { - Big::from_u64(0x10665).sub(&Big::from_u64(0x10666)); -} - -#[test] -#[should_panic] -fn test_sub_underflow_2() { - Big::from_small(0).sub(&Big::from_u64(0x123456)); -} - -#[test] -fn test_mul_small() { - assert_eq!(*Big::from_small(7).mul_small(5), Big::from_small(35)); - assert_eq!(*Big::from_small(0xff).mul_small(0xff), Big::from_u64(0xfe01)); - assert_eq!(*Big::from_u64(0xffffff / 13).mul_small(13), Big::from_u64(0xffffff)); -} - -#[test] -#[should_panic] -fn test_mul_small_overflow() { - Big::from_u64(0x800000).mul_small(2); -} - -#[test] -fn test_mul_pow2() { - assert_eq!(*Big::from_small(0x7).mul_pow2(4), Big::from_small(0x70)); - assert_eq!(*Big::from_small(0xff).mul_pow2(1), Big::from_u64(0x1fe)); - assert_eq!(*Big::from_small(0xff).mul_pow2(12), Big::from_u64(0xff000)); - assert_eq!(*Big::from_small(0x1).mul_pow2(23), Big::from_u64(0x800000)); - assert_eq!(*Big::from_u64(0x123).mul_pow2(0), Big::from_u64(0x123)); - assert_eq!(*Big::from_u64(0x123).mul_pow2(7), Big::from_u64(0x9180)); - assert_eq!(*Big::from_u64(0x123).mul_pow2(15), Big::from_u64(0x918000)); - assert_eq!(*Big::from_small(0).mul_pow2(23), Big::from_small(0)); -} - -#[test] -#[should_panic] -fn test_mul_pow2_overflow_1() { - Big::from_u64(0x1).mul_pow2(24); -} - -#[test] -#[should_panic] -fn test_mul_pow2_overflow_2() { - Big::from_u64(0x123).mul_pow2(16); -} - -#[test] -fn test_mul_pow5() { - assert_eq!(*Big::from_small(42).mul_pow5(0), Big::from_small(42)); - assert_eq!(*Big::from_small(1).mul_pow5(2), Big::from_small(25)); - assert_eq!(*Big::from_small(1).mul_pow5(4), Big::from_u64(25 * 25)); - assert_eq!(*Big::from_small(4).mul_pow5(3), Big::from_u64(500)); - assert_eq!(*Big::from_small(140).mul_pow5(2), Big::from_u64(25 * 140)); - assert_eq!(*Big::from_small(25).mul_pow5(1), Big::from_small(125)); - assert_eq!(*Big::from_small(125).mul_pow5(7), Big::from_u64(9765625)); - assert_eq!(*Big::from_small(0).mul_pow5(127), Big::from_small(0)); -} - -#[test] -#[should_panic] -fn test_mul_pow5_overflow_1() { - Big::from_small(1).mul_pow5(12); -} - -#[test] -#[should_panic] -fn test_mul_pow5_overflow_2() { - Big::from_small(230).mul_pow5(8); -} - -#[test] -fn test_mul_digits() { - assert_eq!(*Big::from_small(3).mul_digits(&[5]), Big::from_small(15)); - assert_eq!(*Big::from_small(0xff).mul_digits(&[0xff]), Big::from_u64(0xfe01)); - assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), Big::from_u64(0x4edc2)); - assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), Big::from_u64(0x7530c3)); - assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), Big::from_u64(0x3ae13e)); - assert_eq!(*Big::from_u64(0xffffff / 13).mul_digits(&[13]), Big::from_u64(0xffffff)); - assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), Big::from_u64(0xffffff)); -} - -#[test] -#[should_panic] -fn test_mul_digits_overflow_1() { - Big::from_u64(0x800000).mul_digits(&[2]); -} - -#[test] -#[should_panic] -fn test_mul_digits_overflow_2() { - Big::from_u64(0x1000).mul_digits(&[0, 0x10]); -} - -#[test] -fn test_div_rem_small() { - let as_val = |(q, r): (&mut Big, u8)| (q.clone(), r); - assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), (Big::from_small(17), 0)); - assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), (Big::from_small(15), 15)); - assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), (Big::from_small(0), 3)); - assert_eq!( - as_val(Big::from_u64(0xffffff).div_rem_small(123)), - (Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8) - ); - assert_eq!( - as_val(Big::from_u64(0x10000).div_rem_small(123)), - (Big::from_u64(0x10000 / 123), (0x10000u64 % 123) as u8) - ); -} - -#[test] -fn test_div_rem() { - fn div_rem(n: u64, d: u64) -> (Big, Big) { - let mut q = Big::from_small(42); - let mut r = Big::from_small(42); - Big::from_u64(n).div_rem(&Big::from_u64(d), &mut q, &mut r); - (q, r) - } - assert_eq!(div_rem(1, 1), (Big::from_small(1), Big::from_small(0))); - assert_eq!(div_rem(4, 3), (Big::from_small(1), Big::from_small(1))); - assert_eq!(div_rem(1, 7), (Big::from_small(0), Big::from_small(1))); - assert_eq!(div_rem(45, 9), (Big::from_small(5), Big::from_small(0))); - assert_eq!(div_rem(103, 9), (Big::from_small(11), Big::from_small(4))); - assert_eq!(div_rem(123456, 77), (Big::from_u64(1603), Big::from_small(25))); - assert_eq!(div_rem(0xffff, 1), (Big::from_u64(0xffff), Big::from_small(0))); - assert_eq!(div_rem(0xeeee, 0xffff), (Big::from_small(0), Big::from_u64(0xeeee))); - assert_eq!(div_rem(2_000_000, 2), (Big::from_u64(1_000_000), Big::from_u64(0))); -} - -#[test] -fn test_is_zero() { - assert!(Big::from_small(0).is_zero()); - assert!(!Big::from_small(3).is_zero()); - assert!(!Big::from_u64(0x123).is_zero()); - assert!(!Big::from_u64(0xffffff).sub(&Big::from_u64(0xfffffe)).is_zero()); - assert!(Big::from_u64(0xffffff).sub(&Big::from_u64(0xffffff)).is_zero()); -} - -#[test] -fn test_get_bit() { - let x = Big::from_small(0b1101); - assert_eq!(x.get_bit(0), 1); - assert_eq!(x.get_bit(1), 0); - assert_eq!(x.get_bit(2), 1); - assert_eq!(x.get_bit(3), 1); - let y = Big::from_u64(1 << 15); - assert_eq!(y.get_bit(14), 0); - assert_eq!(y.get_bit(15), 1); - assert_eq!(y.get_bit(16), 0); -} - -#[test] -#[should_panic] -fn test_get_bit_out_of_range() { - Big::from_small(42).get_bit(24); -} - -#[test] -fn test_bit_length() { - for i in 0..8 * 3 { - // 010000...000 - assert_eq!(Big::from_small(1).mul_pow2(i).bit_length(), i + 1); - } - for i in 1..8 * 3 - 1 { - // 010000...001 - assert_eq!(Big::from_small(1).mul_pow2(i).add(&Big::from_small(1)).bit_length(), i + 1); - // 110000...000 - assert_eq!(Big::from_small(3).mul_pow2(i).bit_length(), i + 2); - } - assert_eq!(Big::from_small(0).bit_length(), 0); - assert_eq!(Big::from_small(1).bit_length(), 1); - assert_eq!(Big::from_small(5).bit_length(), 3); - assert_eq!(Big::from_small(0x18).bit_length(), 5); - assert_eq!(Big::from_u64(0x4073).bit_length(), 15); - assert_eq!(Big::from_u64(0xffffff).bit_length(), 24); -} - -#[test] -fn test_bit_length_32x40() { - for i in 0..32 * 40 { - // 010000...000 - assert_eq!(Big32x40::from_small(1).mul_pow2(i).bit_length(), i + 1); - } - for i in 1..32 * 40 - 1 { - // 010000...001 - assert_eq!( - Big32x40::from_small(1).mul_pow2(i).add(&Big32x40::from_small(1)).bit_length(), - i + 1 - ); - // 110000...000 - assert_eq!(Big32x40::from_small(3).mul_pow2(i).bit_length(), i + 2); - } - assert_eq!(Big32x40::from_small(0).bit_length(), 0); - assert_eq!(Big32x40::from_small(1).bit_length(), 1); - assert_eq!(Big32x40::from_small(5).bit_length(), 3); - assert_eq!(Big32x40::from_small(0x18).bit_length(), 5); - assert_eq!(Big32x40::from_u64(0x4073).bit_length(), 15); - assert_eq!(Big32x40::from_u64(0xffffff).bit_length(), 24); - assert_eq!(Big32x40::from_u64(0xffffffffffffffff).bit_length(), 64); -} - -#[test] -fn test_ord() { - assert!(Big::from_u64(0) < Big::from_u64(0xffffff)); - assert!(Big::from_u64(0x102) < Big::from_u64(0x201)); -} - -#[test] -fn test_fmt() { - assert_eq!(format!("{:?}", Big::from_u64(0)), "0x0"); - assert_eq!(format!("{:?}", Big::from_u64(0x1)), "0x1"); - assert_eq!(format!("{:?}", Big::from_u64(0x12)), "0x12"); - assert_eq!(format!("{:?}", Big::from_u64(0x123)), "0x1_23"); - assert_eq!(format!("{:?}", Big::from_u64(0x1234)), "0x12_34"); - assert_eq!(format!("{:?}", Big::from_u64(0x12345)), "0x1_23_45"); - assert_eq!(format!("{:?}", Big::from_u64(0x123456)), "0x12_34_56"); -} diff --git a/library/core/tests/num/const_from.rs b/library/core/tests/num/const_from.rs deleted file mode 100644 index fa58e771879..00000000000 --- a/library/core/tests/num/const_from.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* FIXME(#110395) -#[test] -fn from() { - use core::convert::TryFrom; - use core::num::TryFromIntError; - - // From - const FROM: i64 = i64::from(1i32); - assert_eq!(FROM, 1i64); - - // From int to float - const FROM_F64: f64 = f64::from(42u8); - assert_eq!(FROM_F64, 42f64); - - // Upper bounded - const U8_FROM_U16: Result = u8::try_from(1u16); - assert_eq!(U8_FROM_U16, Ok(1u8)); - - // Both bounded - const I8_FROM_I16: Result = i8::try_from(1i16); - assert_eq!(I8_FROM_I16, Ok(1i8)); - - // Lower bounded - const I16_FROM_U16: Result = i16::try_from(1u16); - assert_eq!(I16_FROM_U16, Ok(1i16)); -} -*/ diff --git a/library/core/tests/num/dec2flt/float.rs b/library/core/tests/num/dec2flt/float.rs deleted file mode 100644 index 7a9587a18d0..00000000000 --- a/library/core/tests/num/dec2flt/float.rs +++ /dev/null @@ -1,33 +0,0 @@ -use core::num::dec2flt::float::RawFloat; - -#[test] -fn test_f32_integer_decode() { - assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); - assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); - assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); - assert_eq!(0f32.integer_decode(), (0, -150, 1)); - assert_eq!((-0f32).integer_decode(), (0, -150, -1)); - assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1)); - assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (12582912, 105)); -} - -#[test] -fn test_f64_integer_decode() { - assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); - assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); - assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); - assert_eq!(0f64.integer_decode(), (0, -1075, 1)); - assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); - assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1)); - assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (6755399441055744, 972)); -} diff --git a/library/core/tests/num/dec2flt/lemire.rs b/library/core/tests/num/dec2flt/lemire.rs deleted file mode 100644 index f71bbb7c7a3..00000000000 --- a/library/core/tests/num/dec2flt/lemire.rs +++ /dev/null @@ -1,53 +0,0 @@ -use core::num::dec2flt::lemire::compute_float; - -fn compute_float32(q: i64, w: u64) -> (i32, u64) { - let fp = compute_float::(q, w); - (fp.e, fp.f) -} - -fn compute_float64(q: i64, w: u64) -> (i32, u64) { - let fp = compute_float::(q, w); - (fp.e, fp.f) -} - -#[test] -fn compute_float_f32_rounding() { - // These test near-halfway cases for single-precision floats. - assert_eq!(compute_float32(0, 16777216), (151, 0)); - assert_eq!(compute_float32(0, 16777217), (151, 0)); - assert_eq!(compute_float32(0, 16777218), (151, 1)); - assert_eq!(compute_float32(0, 16777219), (151, 2)); - assert_eq!(compute_float32(0, 16777220), (151, 2)); - - // These are examples of the above tests, with - // digits from the exponent shifted to the mantissa. - assert_eq!(compute_float32(-10, 167772160000000000), (151, 0)); - assert_eq!(compute_float32(-10, 167772170000000000), (151, 0)); - assert_eq!(compute_float32(-10, 167772180000000000), (151, 1)); - // Let's check the lines to see if anything is different in table... - assert_eq!(compute_float32(-10, 167772190000000000), (151, 2)); - assert_eq!(compute_float32(-10, 167772200000000000), (151, 2)); -} - -#[test] -fn compute_float_f64_rounding() { - // These test near-halfway cases for double-precision floats. - assert_eq!(compute_float64(0, 9007199254740992), (1076, 0)); - assert_eq!(compute_float64(0, 9007199254740993), (1076, 0)); - assert_eq!(compute_float64(0, 9007199254740994), (1076, 1)); - assert_eq!(compute_float64(0, 9007199254740995), (1076, 2)); - assert_eq!(compute_float64(0, 9007199254740996), (1076, 2)); - assert_eq!(compute_float64(0, 18014398509481984), (1077, 0)); - assert_eq!(compute_float64(0, 18014398509481986), (1077, 0)); - assert_eq!(compute_float64(0, 18014398509481988), (1077, 1)); - assert_eq!(compute_float64(0, 18014398509481990), (1077, 2)); - assert_eq!(compute_float64(0, 18014398509481992), (1077, 2)); - - // These are examples of the above tests, with - // digits from the exponent shifted to the mantissa. - assert_eq!(compute_float64(-3, 9007199254740992000), (1076, 0)); - assert_eq!(compute_float64(-3, 9007199254740993000), (1076, 0)); - assert_eq!(compute_float64(-3, 9007199254740994000), (1076, 1)); - assert_eq!(compute_float64(-3, 9007199254740995000), (1076, 2)); - assert_eq!(compute_float64(-3, 9007199254740996000), (1076, 2)); -} diff --git a/library/core/tests/num/dec2flt/mod.rs b/library/core/tests/num/dec2flt/mod.rs deleted file mode 100644 index 874e0ec7093..00000000000 --- a/library/core/tests/num/dec2flt/mod.rs +++ /dev/null @@ -1,129 +0,0 @@ -#![allow(overflowing_literals)] - -mod float; -mod lemire; -mod parse; - -// Take a float literal, turn it into a string in various ways (that are all trusted -// to be correct) and see if those strings are parsed back to the value of the literal. -// Requires a *polymorphic literal*, i.e., one that can serve as f64 as well as f32. -macro_rules! test_literal { - ($x: expr) => {{ - let x32: f32 = $x; - let x64: f64 = $x; - let inputs = &[stringify!($x).into(), format!("{:?}", x64), format!("{:e}", x64)]; - for input in inputs { - assert_eq!(input.parse(), Ok(x64)); - assert_eq!(input.parse(), Ok(x32)); - let neg_input = format!("-{input}"); - assert_eq!(neg_input.parse(), Ok(-x64)); - assert_eq!(neg_input.parse(), Ok(-x32)); - } - }}; -} - -#[test] -fn ordinary() { - test_literal!(1.0); - test_literal!(3e-5); - test_literal!(0.1); - test_literal!(12345.); - test_literal!(0.9999999); - test_literal!(2.2250738585072014e-308); -} - -#[test] -fn special_code_paths() { - test_literal!(36893488147419103229.0); // 2^65 - 3, triggers half-to-even with even significand - test_literal!(101e-33); // Triggers the tricky underflow case in AlgorithmM (for f32) - test_literal!(1e23); // Triggers AlgorithmR - test_literal!(2075e23); // Triggers another path through AlgorithmR - test_literal!(8713e-23); // ... and yet another. -} - -#[test] -fn large() { - test_literal!(1e300); - test_literal!(123456789.34567e250); - test_literal!(943794359898089732078308743689303290943794359843568973207830874368930329.); -} - -#[test] -fn subnormals() { - test_literal!(5e-324); - test_literal!(91e-324); - test_literal!(1e-322); - test_literal!(13245643e-320); - test_literal!(2.22507385851e-308); - test_literal!(2.1e-308); - test_literal!(4.9406564584124654e-324); -} - -#[test] -fn infinity() { - test_literal!(1e400); - test_literal!(1e309); - test_literal!(2e308); - test_literal!(1.7976931348624e308); -} - -#[test] -fn zero() { - test_literal!(0.0); - test_literal!(1e-325); - test_literal!(1e-326); - test_literal!(1e-500); -} - -#[test] -fn fast_path_correct() { - // This number triggers the fast path and is handled incorrectly when compiling on - // x86 without SSE2 (i.e., using the x87 FPU stack). - test_literal!(1.448997445238699); -} - -#[test] -fn lonely_dot() { - assert!(".".parse::().is_err()); - assert!(".".parse::().is_err()); -} - -#[test] -fn exponentiated_dot() { - assert!(".e0".parse::().is_err()); - assert!(".e0".parse::().is_err()); -} - -#[test] -fn lonely_sign() { - assert!("+".parse::().is_err()); - assert!("-".parse::().is_err()); -} - -#[test] -fn whitespace() { - assert!(" 1.0".parse::().is_err()); - assert!("1.0 ".parse::().is_err()); -} - -#[test] -fn nan() { - assert!("NaN".parse::().unwrap().is_nan()); - assert!("NaN".parse::().unwrap().is_nan()); -} - -#[test] -fn inf() { - assert_eq!("inf".parse(), Ok(f64::INFINITY)); - assert_eq!("-inf".parse(), Ok(f64::NEG_INFINITY)); - assert_eq!("inf".parse(), Ok(f32::INFINITY)); - assert_eq!("-inf".parse(), Ok(f32::NEG_INFINITY)); -} - -#[test] -fn massive_exponent() { - let max = i64::MAX; - assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY)); - assert_eq!(format!("1e-{max}000").parse(), Ok(0.0)); - assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY)); -} diff --git a/library/core/tests/num/dec2flt/parse.rs b/library/core/tests/num/dec2flt/parse.rs deleted file mode 100644 index 4a5d24ba7d5..00000000000 --- a/library/core/tests/num/dec2flt/parse.rs +++ /dev/null @@ -1,177 +0,0 @@ -use core::num::dec2flt::number::Number; -use core::num::dec2flt::parse::parse_number; -use core::num::dec2flt::{dec2flt, pfe_invalid}; - -fn new_number(e: i64, m: u64) -> Number { - Number { exponent: e, mantissa: m, negative: false, many_digits: false } -} - -#[test] -fn missing_pieces() { - let permutations = &[".e", "1e", "e4", "e", ".12e", "321.e", "32.12e+", "12.32e-"]; - for &s in permutations { - assert_eq!(dec2flt::(s), Err(pfe_invalid())); - } -} - -#[test] -fn invalid_chars() { - let invalid = "r,?(&input) == error, "did not reject invalid {:?}", input); - } - } - } -} - -fn parse_positive(s: &[u8]) -> Option { - parse_number(s) -} - -#[test] -fn valid() { - assert_eq!(parse_positive(b"123.456e789"), Some(new_number(786, 123456))); - assert_eq!(parse_positive(b"123.456e+789"), Some(new_number(786, 123456))); - assert_eq!(parse_positive(b"123.456e-789"), Some(new_number(-792, 123456))); - assert_eq!(parse_positive(b".050"), Some(new_number(-3, 50))); - assert_eq!(parse_positive(b"999"), Some(new_number(0, 999))); - assert_eq!(parse_positive(b"1.e300"), Some(new_number(300, 1))); - assert_eq!(parse_positive(b".1e300"), Some(new_number(299, 1))); - assert_eq!(parse_positive(b"101e-33"), Some(new_number(-33, 101))); - let zeros = "0".repeat(25); - let s = format!("1.5e{zeros}"); - assert_eq!(parse_positive(s.as_bytes()), Some(new_number(-1, 15))); -} - -macro_rules! assert_float_result_bits_eq { - ($bits:literal, $ty:ty, $str:literal) => {{ - let p = dec2flt::<$ty>($str); - assert_eq!(p.map(|x| x.to_bits()), Ok($bits)); - }}; -} - -#[test] -fn issue31109() { - // Regression test for #31109. - // Ensure the test produces a valid float with the expected bit pattern. - assert_float_result_bits_eq!( - 0x3fd5555555555555, - f64, - "0.3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333" - ); -} - -#[test] -fn issue31407() { - // Regression test for #31407. - // Ensure the test produces a valid float with the expected bit pattern. - assert_float_result_bits_eq!( - 0x1752a64e34ba0d3, - f64, - "1234567890123456789012345678901234567890e-340" - ); - assert_float_result_bits_eq!( - 0xfffffffffffff, - f64, - "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718749999999999999999999999999999999999999e-308" - ); - assert_float_result_bits_eq!( - 0x10000000000000, - f64, - "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308" - ); - assert_float_result_bits_eq!( - 0x10000000000000, - f64, - "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000222507385850720138309023271733240406421921598046233183055332741688720443481391819585428315901251102056406733973103581100515243416155346010885601238537771882113077799353200233047961014744258363607192156504694250373420837525080665061665815894872049117996859163964850063590877011830487479978088775374994945158045160505091539985658247081864511353793580499211598108576605199243335211435239014879569960959128889160299264151106346631339366347758651302937176204732563178148566435087212282863764204484681140761391147706280168985324411002416144742161856716615054015428508471675290190316132277889672970737312333408698898317506783884692609277397797285865965494109136909540613646756870239867831529068098461721092462539672851562500000000000000001" - ); - assert_float_result_bits_eq!( - 0x7fefffffffffffff, - f64, - "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999" - ); - assert_float_result_bits_eq!(0x0, f64, "2.47032822920623272e-324"); - assert_float_result_bits_eq!( - 0x8000000, - f64, - "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316" - ); - assert_float_result_bits_eq!( - 0x10000, - f64, - "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875E-319" - ); - assert_float_result_bits_eq!( - 0x800000000100, - f64, - "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125E-310" - ); - assert_float_result_bits_eq!( - 0x10800, - f64, - "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875E-319" - ); - assert_float_result_bits_eq!( - 0x0, - f64, - "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999e-324" - ); - assert_float_result_bits_eq!( - 0x0, - f64, - "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125e-324" - ); - assert_float_result_bits_eq!( - 0x1, - f64, - "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324" - ); - assert_float_result_bits_eq!( - 0x1, - f64, - "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324" - ); - assert_float_result_bits_eq!( - 0x2, - f64, - "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324" - ); - assert_float_result_bits_eq!( - 0x2, - f64, - "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324" - ); - assert_float_result_bits_eq!( - 0x6c9a143590c14, - f64, - "94393431193180696942841837085033647913224148539854e-358" - ); - assert_float_result_bits_eq!( - 0x7802665fd9600, - f64, - "104308485241983990666713401708072175773165034278685682646111762292409330928739751702404658197872319129036519947435319418387839758990478549477777586673075945844895981012024387992135617064532141489278815239849108105951619997829153633535314849999674266169258928940692239684771590065027025835804863585454872499320500023126142553932654370362024104462255244034053203998964360882487378334860197725139151265590832887433736189468858614521708567646743455601905935595381852723723645799866672558576993978025033590728687206296379801363024094048327273913079612469982585674824156000783167963081616214710691759864332339239688734656548790656486646106983450809073750535624894296242072010195710276073042036425579852459556183541199012652571123898996574563824424330960027873516082763671875e-1075" - ); -} - -#[test] -fn many_digits() { - // Check large numbers of digits to ensure we have cases where significant - // digits (above Decimal::MAX_DIGITS) occurs. - assert_float_result_bits_eq!( - 0x7ffffe, - f32, - "1.175494140627517859246175898662808184331245864732796240031385942718174675986064769972472277004271745681762695312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-38" - ); - assert_float_result_bits_eq!( - 0x7ffffe, - f32, - "1.175494140627517859246175898662808184331245864732796240031385942718174675986064769972472277004271745681762695312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-38" - ); -} diff --git a/library/core/tests/num/float_iter_sum_identity.rs b/library/core/tests/num/float_iter_sum_identity.rs deleted file mode 100644 index 6d3224522a8..00000000000 --- a/library/core/tests/num/float_iter_sum_identity.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[test] -fn f32_ref() { - let x: f32 = -0.0; - let still_x: f32 = [x].iter().sum(); - assert_eq!(1. / x, 1. / still_x) -} - -#[test] -fn f32_own() { - let x: f32 = -0.0; - let still_x: f32 = [x].into_iter().sum(); - assert_eq!(1. / x, 1. / still_x) -} - -#[test] -fn f64_ref() { - let x: f64 = -0.0; - let still_x: f64 = [x].iter().sum(); - assert_eq!(1. / x, 1. / still_x) -} - -#[test] -fn f64_own() { - let x: f64 = -0.0; - let still_x: f64 = [x].into_iter().sum(); - assert_eq!(1. / x, 1. / still_x) -} diff --git a/library/core/tests/num/flt2dec/estimator.rs b/library/core/tests/num/flt2dec/estimator.rs deleted file mode 100644 index da203b5f362..00000000000 --- a/library/core/tests/num/flt2dec/estimator.rs +++ /dev/null @@ -1,62 +0,0 @@ -use core::num::flt2dec::estimator::*; - -#[test] -fn test_estimate_scaling_factor() { - macro_rules! assert_almost_eq { - ($actual:expr, $expected:expr) => {{ - let actual = $actual; - let expected = $expected; - println!( - "{} - {} = {} - {} = {}", - stringify!($expected), - stringify!($actual), - expected, - actual, - expected - actual - ); - assert!( - expected == actual || expected == actual + 1, - "expected {}, actual {}", - expected, - actual - ); - }}; - } - - assert_almost_eq!(estimate_scaling_factor(1, 0), 0); - assert_almost_eq!(estimate_scaling_factor(2, 0), 1); - assert_almost_eq!(estimate_scaling_factor(10, 0), 1); - assert_almost_eq!(estimate_scaling_factor(11, 0), 2); - assert_almost_eq!(estimate_scaling_factor(100, 0), 2); - assert_almost_eq!(estimate_scaling_factor(101, 0), 3); - assert_almost_eq!(estimate_scaling_factor(10000000000000000000, 0), 19); - assert_almost_eq!(estimate_scaling_factor(10000000000000000001, 0), 20); - - // 1/2^20 = 0.00000095367... - assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000, -20), -6); - assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000 + 1, -20), -5); - assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000, -20), -5); - assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000 + 1, -20), -4); - assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000, -20), -4); - assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000 + 1, -20), -3); - assert_almost_eq!(estimate_scaling_factor(1048575, -20), 0); - assert_almost_eq!(estimate_scaling_factor(1048576, -20), 0); - assert_almost_eq!(estimate_scaling_factor(1048577, -20), 1); - assert_almost_eq!(estimate_scaling_factor(10485759999999999999, -20), 13); - assert_almost_eq!(estimate_scaling_factor(10485760000000000000, -20), 13); - assert_almost_eq!(estimate_scaling_factor(10485760000000000001, -20), 14); - - // extreme values: - // 2^-1074 = 4.94065... * 10^-324 - // (2^53-1) * 2^971 = 1.79763... * 10^308 - assert_almost_eq!(estimate_scaling_factor(1, -1074), -323); - assert_almost_eq!(estimate_scaling_factor(0x1fffffffffffff, 971), 309); - - // Miri is too slow - let step = if cfg!(miri) { 37 } else { 1 }; - - for i in (-1074..972).step_by(step) { - let expected = super::ldexp_f64(1.0, i).log10().ceil(); - assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16); - } -} diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs deleted file mode 100644 index 3d825224813..00000000000 --- a/library/core/tests/num/flt2dec/mod.rs +++ /dev/null @@ -1,1168 +0,0 @@ -use core::num::flt2dec::{ - DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, Sign, decode, round_up, to_exact_exp_str, - to_exact_fixed_str, to_shortest_exp_str, to_shortest_str, -}; -use core::num::fmt::{Formatted, Part}; -use std::mem::MaybeUninit; -use std::{fmt, str}; - -mod estimator; -mod strategy { - mod dragon; - mod grisu; -} -mod random; - -pub fn decode_finite(v: T) -> Decoded { - match decode(v).1 { - FullDecoded::Finite(decoded) => decoded, - full_decoded => panic!("expected finite, got {full_decoded:?} instead"), - } -} - -macro_rules! check_shortest { - ($f:ident($v:expr) => $buf:expr, $exp:expr) => ( - check_shortest!($f($v) => $buf, $exp; - "shortest mismatch for v={v}: actual {actual:?}, expected {expected:?}", - v = stringify!($v)) - ); - - ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr) => ( - check_shortest!($f{$($k: $v),+} => $buf, $exp; - "shortest mismatch for {v:?}: actual {actual:?}, expected {expected:?}", - v = Decoded { $($k: $v),+ }) - ); - - ($f:ident($v:expr) => $buf:expr, $exp:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ - let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; - let (buf, k) = $f(&decode_finite($v), &mut buf); - assert!((buf, k) == ($buf, $exp), - $fmt, actual = (str::from_utf8(buf).unwrap(), k), - expected = (str::from_utf8($buf).unwrap(), $exp), - $($key = $val),*); - }); - - ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr; - $fmt:expr, $($key:ident = $val:expr),*) => ({ - let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; - let (buf, k) = $f(&Decoded { $($k: $v),+ }, &mut buf); - assert!((buf, k) == ($buf, $exp), - $fmt, actual = (str::from_utf8(buf).unwrap(), k), - expected = (str::from_utf8($buf).unwrap(), $exp), - $($key = $val),*); - }) -} - -macro_rules! try_exact { - ($f:ident($decoded:expr) => $buf:expr, $expected:expr, $expectedk:expr; - $fmt:expr, $($key:ident = $val:expr),*) => ({ - let (buf, k) = $f($decoded, &mut $buf[..$expected.len()], i16::MIN); - assert!((buf, k) == ($expected, $expectedk), - $fmt, actual = (str::from_utf8(buf).unwrap(), k), - expected = (str::from_utf8($expected).unwrap(), $expectedk), - $($key = $val),*); - }) -} - -macro_rules! try_fixed { - ($f:ident($decoded:expr) => $buf:expr, $request:expr, $expected:expr, $expectedk:expr; - $fmt:expr, $($key:ident = $val:expr),*) => ({ - let (buf, k) = $f($decoded, &mut $buf[..], $request); - assert!((buf, k) == ($expected, $expectedk), - $fmt, actual = (str::from_utf8(buf).unwrap(), k), - expected = (str::from_utf8($expected).unwrap(), $expectedk), - $($key = $val),*); - }) -} - -fn ldexp_f32(a: f32, b: i32) -> f32 { - ldexp_f64(a as f64, b) as f32 -} - -fn ldexp_f64(a: f64, b: i32) -> f64 { - extern "C" { - fn ldexp(x: f64, n: i32) -> f64; - } - // SAFETY: assuming a correct `ldexp` has been supplied, the given arguments cannot possibly - // cause undefined behavior - unsafe { ldexp(a, b) } -} - -fn check_exact(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16) -where - T: DecodableFloat, - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), -{ - // use a large enough buffer - let mut buf = [MaybeUninit::new(b'_'); 1024]; - let mut expected_ = [b'_'; 1024]; - - let decoded = decode_finite(v); - let cut = expected.iter().position(|&c| c == b' '); - - // check significant digits - for i in 1..cut.unwrap_or(expected.len() - 1) { - expected_[..i].copy_from_slice(&expected[..i]); - let mut expectedk_ = expectedk; - if expected[i] >= b'5' { - // check if this is a rounding-to-even case. - // we avoid rounding ...x5000... (with infinite zeroes) to ...(x+1) when x is even. - if !(i + 1 < expected.len() - && expected[i - 1] & 1 == 0 - && expected[i] == b'5' - && expected[i + 1] == b' ') - { - // if this returns true, expected_[..i] is all `9`s and being rounded up. - // we should always return `100..00` (`i` digits) instead, since that's - // what we can came up with `i` digits anyway. `round_up` assumes that - // the adjustment to the length is done by caller, which we simply ignore. - if let Some(_) = round_up(&mut expected_[..i]) { - expectedk_ += 1; - } - } - } - - try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk_; - "exact sigdigit mismatch for v={v}, i={i}: \ - actual {actual:?}, expected {expected:?}", - v = vstr, i = i); - try_fixed!(f(&decoded) => &mut buf, expectedk_ - i as i16, &expected_[..i], expectedk_; - "fixed sigdigit mismatch for v={v}, i={i}: \ - actual {actual:?}, expected {expected:?}", - v = vstr, i = i); - } - - // check exact rounding for zero- and negative-width cases - let start; - if expected[0] > b'5' { - try_fixed!(f(&decoded) => &mut buf, expectedk, b"1", expectedk + 1; - "zero-width rounding-up mismatch for v={v}: \ - actual {actual:?}, expected {expected:?}", - v = vstr); - start = 1; - } else { - start = 0; - } - for i in start..-10 { - try_fixed!(f(&decoded) => &mut buf, expectedk - i, b"", expectedk; - "rounding-down mismatch for v={v}, i={i}: \ - actual {actual:?}, expected {expected:?}", - v = vstr, i = -i); - } - - // check infinite zero digits - if let Some(cut) = cut { - for i in cut..expected.len() - 1 { - expected_[..cut].copy_from_slice(&expected[..cut]); - for c in &mut expected_[cut..i] { - *c = b'0'; - } - - try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk; - "exact infzero mismatch for v={v}, i={i}: \ - actual {actual:?}, expected {expected:?}", - v = vstr, i = i); - try_fixed!(f(&decoded) => &mut buf, expectedk - i as i16, &expected_[..i], expectedk; - "fixed infzero mismatch for v={v}, i={i}: \ - actual {actual:?}, expected {expected:?}", - v = vstr, i = i); - } - } -} - -trait TestableFloat: DecodableFloat + fmt::Display { - /// Returns `x * 2^exp`. Almost same to `std::{f32,f64}::ldexp`. - /// This is used for testing. - fn ldexpi(f: i64, exp: isize) -> Self; -} - -impl TestableFloat for f32 { - fn ldexpi(f: i64, exp: isize) -> Self { - f as Self * (exp as Self).exp2() - } -} - -impl TestableFloat for f64 { - fn ldexpi(f: i64, exp: isize) -> Self { - f as Self * (exp as Self).exp2() - } -} - -fn check_exact_one(mut f: F, x: i64, e: isize, tstr: &str, expected: &[u8], expectedk: i16) -where - T: TestableFloat, - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), -{ - // use a large enough buffer - let mut buf = [MaybeUninit::new(b'_'); 1024]; - let v: T = TestableFloat::ldexpi(x, e); - let decoded = decode_finite(v); - - try_exact!(f(&decoded) => &mut buf, &expected, expectedk; - "exact mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}", - x = x, e = e, t = tstr); - try_fixed!(f(&decoded) => &mut buf, expectedk - expected.len() as i16, &expected, expectedk; - "fixed mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}", - x = x, e = e, t = tstr); -} - -macro_rules! check_exact { - ($f:ident($v:expr) => $buf:expr, $exp:expr) => { - check_exact(|d, b, k| $f(d, b, k), $v, stringify!($v), $buf, $exp) - }; -} - -macro_rules! check_exact_one { - ($f:ident($x:expr, $e:expr; $t:ty) => $buf:expr, $exp:expr) => { - check_exact_one::<_, $t>(|d, b, k| $f(d, b, k), $x, $e, stringify!($t), $buf, $exp) - }; -} - -// in the following comments, three numbers are spaced by 1 ulp apart, -// and the second one is being formatted. -// -// some tests are derived from [1]. -// -// [1] Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion -// ftp://ftp.ee.lbl.gov/testbase-report.ps.Z - -pub fn f32_shortest_sanity_test(mut f: F) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), -{ - // 0.0999999940395355224609375 - // 0.100000001490116119384765625 - // 0.10000000894069671630859375 - check_shortest!(f(0.1f32) => b"1", 0); - - // 0.333333313465118408203125 - // 0.3333333432674407958984375 (1/3 in the default rounding) - // 0.33333337306976318359375 - check_shortest!(f(1.0f32/3.0) => b"33333334", 0); - - // 10^1 * 0.31415917873382568359375 - // 10^1 * 0.31415920257568359375 - // 10^1 * 0.31415922641754150390625 - check_shortest!(f(3.141592f32) => b"3141592", 1); - - // 10^18 * 0.31415916243714048 - // 10^18 * 0.314159196796878848 - // 10^18 * 0.314159231156617216 - check_shortest!(f(3.141592e17f32) => b"3141592", 18); - - // regression test for decoders - // 10^8 * 0.3355443 - // 10^8 * 0.33554432 - // 10^8 * 0.33554436 - check_shortest!(f(ldexp_f32(1.0, 25)) => b"33554432", 8); - - // 10^39 * 0.340282326356119256160033759537265639424 - // 10^39 * 0.34028234663852885981170418348451692544 - // 10^39 * 0.340282366920938463463374607431768211456 - check_shortest!(f(f32::MAX) => b"34028235", 39); - - // 10^-37 * 0.1175494210692441075487029444849287348827... - // 10^-37 * 0.1175494350822287507968736537222245677818... - // 10^-37 * 0.1175494490952133940450443629595204006810... - check_shortest!(f(f32::MIN_POSITIVE) => b"11754944", -37); - - // 10^-44 * 0 - // 10^-44 * 0.1401298464324817070923729583289916131280... - // 10^-44 * 0.2802596928649634141847459166579832262560... - let minf32 = ldexp_f32(1.0, -149); - check_shortest!(f(minf32) => b"1", -44); -} - -pub fn f32_exact_sanity_test(mut f: F) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), -{ - let minf32 = ldexp_f32(1.0, -149); - - check_exact!(f(0.1f32) => b"100000001490116119384765625 ", 0); - check_exact!(f(0.5f32) => b"5 ", 0); - check_exact!(f(1.0f32/3.0) => b"3333333432674407958984375 ", 0); - check_exact!(f(3.141592f32) => b"31415920257568359375 ", 1); - check_exact!(f(3.141592e17f32) => b"314159196796878848 ", 18); - check_exact!(f(f32::MAX) => b"34028234663852885981170418348451692544 ", 39); - check_exact!(f(f32::MIN_POSITIVE) => b"1175494350822287507968736537222245677818", -37); - check_exact!(f(minf32) => b"1401298464324817070923729583289916131280", -44); - - // [1], Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP - check_exact_one!(f(12676506, -102; f32) => b"2", -23); - check_exact_one!(f(12676506, -103; f32) => b"12", -23); - check_exact_one!(f(15445013, 86; f32) => b"119", 34); - check_exact_one!(f(13734123, -138; f32) => b"3941", -34); - check_exact_one!(f(12428269, -130; f32) => b"91308", -32); - check_exact_one!(f(15334037, -146; f32) => b"171900", -36); - check_exact_one!(f(11518287, -41; f32) => b"5237910", -5); - check_exact_one!(f(12584953, -145; f32) => b"28216440", -36); - check_exact_one!(f(15961084, -125; f32) => b"375243281", -30); - check_exact_one!(f(14915817, -146; f32) => b"1672120916", -36); - check_exact_one!(f(10845484, -102; f32) => b"21388945814", -23); - check_exact_one!(f(16431059, -61; f32) => b"712583594561", -11); - - // [1], Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP - check_exact_one!(f(16093626, 69; f32) => b"1", 29); - check_exact_one!(f( 9983778, 25; f32) => b"34", 15); - check_exact_one!(f(12745034, 104; f32) => b"259", 39); - check_exact_one!(f(12706553, 72; f32) => b"6001", 29); - check_exact_one!(f(11005028, 45; f32) => b"38721", 21); - check_exact_one!(f(15059547, 71; f32) => b"355584", 29); - check_exact_one!(f(16015691, -99; f32) => b"2526831", -22); - check_exact_one!(f( 8667859, 56; f32) => b"62458507", 24); - check_exact_one!(f(14855922, -82; f32) => b"307213267", -17); - check_exact_one!(f(14855922, -83; f32) => b"1536066333", -17); - check_exact_one!(f(10144164, -110; f32) => b"78147796834", -26); - check_exact_one!(f(13248074, 95; f32) => b"524810279937", 36); -} - -pub fn f64_shortest_sanity_test(mut f: F) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), -{ - // 0.0999999999999999777955395074968691915273... - // 0.1000000000000000055511151231257827021181... - // 0.1000000000000000333066907387546962127089... - check_shortest!(f(0.1f64) => b"1", 0); - - // this example is explicitly mentioned in the paper. - // 10^3 * 0.0999999999999999857891452847979962825775... - // 10^3 * 0.1 (exact) - // 10^3 * 0.1000000000000000142108547152020037174224... - check_shortest!(f(100.0f64) => b"1", 3); - - // 0.3333333333333332593184650249895639717578... - // 0.3333333333333333148296162562473909929394... (1/3 in the default rounding) - // 0.3333333333333333703407674875052180141210... - check_shortest!(f(1.0f64/3.0) => b"3333333333333333", 0); - - // explicit test case for equally closest representations. - // Dragon has its own tie-breaking rule; Grisu should fall back. - // 10^1 * 0.1000007629394531027955395074968691915273... - // 10^1 * 0.100000762939453125 (exact) - // 10^1 * 0.1000007629394531472044604925031308084726... - check_shortest!(f(1.00000762939453125f64) => b"10000076293945313", 1); - - // 10^1 * 0.3141591999999999718085064159822650253772... - // 10^1 * 0.3141592000000000162174274009885266423225... - // 10^1 * 0.3141592000000000606263483859947882592678... - check_shortest!(f(3.141592f64) => b"3141592", 1); - - // 10^18 * 0.314159199999999936 - // 10^18 * 0.3141592 (exact) - // 10^18 * 0.314159200000000064 - check_shortest!(f(3.141592e17f64) => b"3141592", 18); - - // regression test for decoders - // 10^20 * 0.18446744073709549568 - // 10^20 * 0.18446744073709551616 - // 10^20 * 0.18446744073709555712 - check_shortest!(f(ldexp_f64(1.0, 64)) => b"18446744073709552", 20); - - // pathological case: high = 10^23 (exact). tie breaking should always prefer that. - // 10^24 * 0.099999999999999974834176 - // 10^24 * 0.099999999999999991611392 - // 10^24 * 0.100000000000000008388608 - check_shortest!(f(1.0e23f64) => b"1", 24); - - // 10^309 * 0.1797693134862315508561243283845062402343... - // 10^309 * 0.1797693134862315708145274237317043567980... - // 10^309 * 0.1797693134862315907729305190789024733617... - check_shortest!(f(f64::MAX) => b"17976931348623157", 309); - - // 10^-307 * 0.2225073858507200889024586876085859887650... - // 10^-307 * 0.2225073858507201383090232717332404064219... - // 10^-307 * 0.2225073858507201877155878558578948240788... - check_shortest!(f(f64::MIN_POSITIVE) => b"22250738585072014", -307); - - // 10^-323 * 0 - // 10^-323 * 0.4940656458412465441765687928682213723650... - // 10^-323 * 0.9881312916824930883531375857364427447301... - let minf64 = ldexp_f64(1.0, -1074); - check_shortest!(f(minf64) => b"5", -323); -} - -pub fn f64_exact_sanity_test(mut f: F) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), -{ - let minf64 = ldexp_f64(1.0, -1074); - - check_exact!(f(0.1f64) => b"1000000000000000055511151231257827021181", 0); - check_exact!(f(0.45f64) => b"4500000000000000111022302462515654042363", 0); - check_exact!(f(0.5f64) => b"5 ", 0); - check_exact!(f(0.95f64) => b"9499999999999999555910790149937383830547", 0); - check_exact!(f(100.0f64) => b"1 ", 3); - check_exact!(f(999.5f64) => b"9995000000000000000000000000000000000000", 3); - check_exact!(f(1.0f64/3.0) => b"3333333333333333148296162562473909929394", 0); - check_exact!(f(3.141592f64) => b"3141592000000000162174274009885266423225", 1); - check_exact!(f(3.141592e17f64) => b"3141592 ", 18); - check_exact!(f(1.0e23f64) => b"99999999999999991611392 ", 23); - check_exact!(f(f64::MAX) => b"1797693134862315708145274237317043567980", 309); - check_exact!(f(f64::MIN_POSITIVE) => b"2225073858507201383090232717332404064219", -307); - check_exact!(f(minf64) => b"4940656458412465441765687928682213723650\ - 5980261432476442558568250067550727020875\ - 1865299836361635992379796564695445717730\ - 9266567103559397963987747960107818781263\ - 0071319031140452784581716784898210368871\ - 8636056998730723050006387409153564984387\ - 3124733972731696151400317153853980741262\ - 3856559117102665855668676818703956031062\ - 4931945271591492455329305456544401127480\ - 1297099995419319894090804165633245247571\ - 4786901472678015935523861155013480352649\ - 3472019379026810710749170333222684475333\ - 5720832431936092382893458368060106011506\ - 1698097530783422773183292479049825247307\ - 7637592724787465608477820373446969953364\ - 7017972677717585125660551199131504891101\ - 4510378627381672509558373897335989936648\ - 0994116420570263709027924276754456522908\ - 7538682506419718265533447265625 ", -323); - - // [1], Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP - check_exact_one!(f(8511030020275656, -342; f64) => b"9", -87); - check_exact_one!(f(5201988407066741, -824; f64) => b"46", -232); - check_exact_one!(f(6406892948269899, 237; f64) => b"141", 88); - check_exact_one!(f(8431154198732492, 72; f64) => b"3981", 38); - check_exact_one!(f(6475049196144587, 99; f64) => b"41040", 46); - check_exact_one!(f(8274307542972842, 726; f64) => b"292084", 235); - check_exact_one!(f(5381065484265332, -456; f64) => b"2891946", -121); - check_exact_one!(f(6761728585499734, -1057; f64) => b"43787718", -302); - check_exact_one!(f(7976538478610756, 376; f64) => b"122770163", 130); - check_exact_one!(f(5982403858958067, 377; f64) => b"1841552452", 130); - check_exact_one!(f(5536995190630837, 93; f64) => b"54835744350", 44); - check_exact_one!(f(7225450889282194, 710; f64) => b"389190181146", 230); - check_exact_one!(f(7225450889282194, 709; f64) => b"1945950905732", 230); - check_exact_one!(f(8703372741147379, 117; f64) => b"14460958381605", 52); - check_exact_one!(f(8944262675275217, -1001; f64) => b"417367747458531", -285); - check_exact_one!(f(7459803696087692, -707; f64) => b"1107950772878888", -196); - check_exact_one!(f(6080469016670379, -381; f64) => b"12345501366327440", -98); - check_exact_one!(f(8385515147034757, 721; f64) => b"925031711960365024", 233); - check_exact_one!(f(7514216811389786, -828; f64) => b"4198047150284889840", -233); - check_exact_one!(f(8397297803260511, -345; f64) => b"11716315319786511046", -87); - check_exact_one!(f(6733459239310543, 202; f64) => b"432810072844612493629", 77); - check_exact_one!(f(8091450587292794, -473; f64) => b"3317710118160031081518", -126); - - // [1], Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP - check_exact_one!(f(6567258882077402, 952; f64) => b"3", 303); - check_exact_one!(f(6712731423444934, 535; f64) => b"76", 177); - check_exact_one!(f(6712731423444934, 534; f64) => b"378", 177); - check_exact_one!(f(5298405411573037, -957; f64) => b"4350", -272); - check_exact_one!(f(5137311167659507, -144; f64) => b"23037", -27); - check_exact_one!(f(6722280709661868, 363; f64) => b"126301", 126); - check_exact_one!(f(5344436398034927, -169; f64) => b"7142211", -35); - check_exact_one!(f(8369123604277281, -853; f64) => b"13934574", -240); - check_exact_one!(f(8995822108487663, -780; f64) => b"141463449", -218); - check_exact_one!(f(8942832835564782, -383; f64) => b"4539277920", -99); - check_exact_one!(f(8942832835564782, -384; f64) => b"22696389598", -99); - check_exact_one!(f(8942832835564782, -385; f64) => b"113481947988", -99); - check_exact_one!(f(6965949469487146, -249; f64) => b"7700366561890", -59); - check_exact_one!(f(6965949469487146, -250; f64) => b"38501832809448", -59); - check_exact_one!(f(6965949469487146, -251; f64) => b"192509164047238", -59); - check_exact_one!(f(7487252720986826, 548; f64) => b"6898586531774201", 181); - check_exact_one!(f(5592117679628511, 164; f64) => b"13076622631878654", 66); - check_exact_one!(f(8887055249355788, 665; f64) => b"136052020756121240", 217); - check_exact_one!(f(6994187472632449, 690; f64) => b"3592810217475959676", 224); - check_exact_one!(f(8797576579012143, 588; f64) => b"89125197712484551899", 193); - check_exact_one!(f(7363326733505337, 272; f64) => b"558769757362301140950", 98); - check_exact_one!(f(8549497411294502, -448; f64) => b"1176257830728540379990", -118); -} - -pub fn more_shortest_sanity_test(mut f: F) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), -{ - check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, - exp: 0, inclusive: true} => b"1", 18); - check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, - exp: 0, inclusive: false} => b"99999999999999999", 17); -} - -fn to_string_with_parts(mut f: F) -> String -where - F: for<'a> FnMut(&'a mut [MaybeUninit], &'a mut [MaybeUninit>]) -> Formatted<'a>, -{ - let mut buf = [MaybeUninit::new(0); 1024]; - let mut parts = [MaybeUninit::new(Part::Zero(0)); 16]; - let formatted = f(&mut buf, &mut parts); - let mut ret = vec![0; formatted.len()]; - assert_eq!(formatted.write(&mut ret), Some(ret.len())); - String::from_utf8(ret).unwrap() -} - -pub fn to_shortest_str_test(mut f_: F) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), -{ - use core::num::flt2dec::Sign::*; - - fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String - where - T: DecodableFloat, - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), - { - to_string_with_parts(|buf, parts| { - to_shortest_str(|d, b| f(d, b), v, sign, frac_digits, buf, parts) - }) - } - - let f = &mut f_; - - assert_eq!(to_string(f, 0.0, Minus, 0), "0"); - assert_eq!(to_string(f, 0.0, Minus, 0), "0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); - assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); - assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); - - assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 0), "+inf"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); - assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3.14"); - assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); - assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3.14"); - assert_eq!(to_string(f, 3.14, Minus, 1), "3.14"); - assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); - assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); - - assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750"); - - assert_eq!(to_string(f, 1.9971e20, Minus, 0), "199710000000000000000"); - assert_eq!(to_string(f, 1.9971e20, Minus, 1), "199710000000000000000.0"); - assert_eq!(to_string(f, 1.9971e20, Minus, 8), "199710000000000000000.00000000"); - - assert_eq!(to_string(f, f32::MAX, Minus, 0), format!("34028235{:0>31}", "")); - assert_eq!(to_string(f, f32::MAX, Minus, 1), format!("34028235{:0>31}.0", "")); - assert_eq!(to_string(f, f32::MAX, Minus, 8), format!("34028235{:0>31}.00000000", "")); - - let minf32 = ldexp_f32(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, 0), format!("0.{:0>44}1", "")); - assert_eq!(to_string(f, minf32, Minus, 45), format!("0.{:0>44}1", "")); - assert_eq!(to_string(f, minf32, Minus, 46), format!("0.{:0>44}10", "")); - - assert_eq!(to_string(f, f64::MAX, Minus, 0), format!("17976931348623157{:0>292}", "")); - assert_eq!(to_string(f, f64::MAX, Minus, 1), format!("17976931348623157{:0>292}.0", "")); - assert_eq!(to_string(f, f64::MAX, Minus, 8), format!("17976931348623157{:0>292}.00000000", "")); - - let minf64 = ldexp_f64(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, 0), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, 324), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, 325), format!("0.{:0>323}50", "")); - - if cfg!(miri) { - // Miri is too slow - return; - } - - // very large output - assert_eq!(to_string(f, 1.1, Minus, 80000), format!("1.1{:0>79999}", "")); -} - -pub fn to_shortest_exp_str_test(mut f_: F) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), -{ - use core::num::flt2dec::Sign::*; - - fn to_string(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: bool) -> String - where - T: DecodableFloat, - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), - { - to_string_with_parts(|buf, parts| { - to_shortest_exp_str(|d, b| f(d, b), v, sign, exp_bounds, upper, buf, parts) - }) - } - - let f = &mut f_; - - assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); - assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); - assert_eq!(to_string(f, 0.0, MinusPlus, (-4, 16), false), "+0"); - assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "-0"); - assert_eq!(to_string(f, 0.0, Minus, (0, 0), true), "0E0"); - assert_eq!(to_string(f, 0.0, Minus, (0, 0), false), "0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, (5, 9), false), "+0e0"); - assert_eq!(to_string(f, -0.0, Minus, (0, 0), true), "-0E0"); - assert_eq!(to_string(f, -0.0, MinusPlus, (5, 9), false), "-0e0"); - - assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), false), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), true), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, (-4, 16), true), "+inf"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), true), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, (5, 9), true), "NaN"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), true), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, (5, 9), true), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, (-4, 16), false), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, (-4, 16), false), "+3.14"); - assert_eq!(to_string(f, -3.14, Minus, (-4, 16), false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlus, (-4, 16), false), "-3.14"); - assert_eq!(to_string(f, 3.14, Minus, (0, 0), true), "3.14E0"); - assert_eq!(to_string(f, 3.14, Minus, (0, 0), false), "3.14e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, (5, 9), false), "+3.14e0"); - assert_eq!(to_string(f, -3.14, Minus, (0, 0), true), "-3.14E0"); - assert_eq!(to_string(f, -3.14, Minus, (0, 0), false), "-3.14e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, (5, 9), false), "-3.14e0"); - - assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); - assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); - assert_eq!(to_string(f, 0.1, MinusPlus, (-4, 16), false), "+0.1"); - assert_eq!(to_string(f, -0.1, Minus, (-4, 16), false), "-0.1"); - assert_eq!(to_string(f, -0.1, MinusPlus, (-4, 16), false), "-0.1"); - assert_eq!(to_string(f, 0.1, Minus, (0, 0), true), "1E-1"); - assert_eq!(to_string(f, 0.1, Minus, (0, 0), false), "1e-1"); - assert_eq!(to_string(f, 0.1, MinusPlus, (5, 9), false), "+1e-1"); - assert_eq!(to_string(f, -0.1, Minus, (0, 0), true), "-1E-1"); - assert_eq!(to_string(f, -0.1, Minus, (0, 0), false), "-1e-1"); - assert_eq!(to_string(f, -0.1, MinusPlus, (5, 9), false), "-1e-1"); - - assert_eq!(to_string(f, 7.5e-11, Minus, (-4, 16), false), "7.5e-11"); - assert_eq!(to_string(f, 7.5e-11, Minus, (-11, 10), false), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, (-10, 11), false), "7.5e-11"); - - assert_eq!(to_string(f, 1.9971e20, Minus, (-4, 16), false), "1.9971e20"); - assert_eq!(to_string(f, 1.9971e20, Minus, (-20, 21), false), "199710000000000000000"); - assert_eq!(to_string(f, 1.9971e20, Minus, (-21, 20), false), "1.9971e20"); - - // the true value of 1.0e23f64 is less than 10^23, but that shouldn't matter here - assert_eq!(to_string(f, 1.0e23, Minus, (22, 23), false), "1e23"); - assert_eq!(to_string(f, 1.0e23, Minus, (23, 24), false), "100000000000000000000000"); - assert_eq!(to_string(f, 1.0e23, Minus, (24, 25), false), "1e23"); - - assert_eq!(to_string(f, f32::MAX, Minus, (-4, 16), false), "3.4028235e38"); - assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38"); - assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", "")); - - let minf32 = ldexp_f32(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, (-4, 16), false), "1e-45"); - assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45"); - assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", "")); - - assert_eq!(to_string(f, f64::MAX, Minus, (-4, 16), false), "1.7976931348623157e308"); - assert_eq!( - to_string(f, f64::MAX, Minus, (-308, 309), false), - format!("17976931348623157{:0>292}", "") - ); - assert_eq!(to_string(f, f64::MAX, Minus, (-309, 308), false), "1.7976931348623157e308"); - - let minf64 = ldexp_f64(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, (-4, 16), false), "5e-324"); - assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324"); - - assert_eq!(to_string(f, 1.1, Minus, (i16::MIN, i16::MAX), false), "1.1"); -} - -pub fn to_exact_exp_str_test(mut f_: F) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), -{ - use core::num::flt2dec::Sign::*; - - fn to_string(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) -> String - where - T: DecodableFloat, - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), - { - to_string_with_parts(|buf, parts| { - to_exact_exp_str(|d, b, l| f(d, b, l), v, sign, ndigits, upper, buf, parts) - }) - } - - let f = &mut f_; - - assert_eq!(to_string(f, 0.0, Minus, 1, true), "0E0"); - assert_eq!(to_string(f, 0.0, Minus, 1, false), "0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1, false), "+0e0"); - assert_eq!(to_string(f, -0.0, Minus, 1, true), "-0E0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 1, false), "-0e0"); - assert_eq!(to_string(f, 0.0, Minus, 2, true), "0.0E0"); - assert_eq!(to_string(f, 0.0, Minus, 2, false), "0.0e0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 2, false), "+0.0e0"); - assert_eq!(to_string(f, -0.0, Minus, 8, false), "-0.0000000e0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8, false), "-0.0000000e0"); - - assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, false), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, true), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 1, true), "+inf"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, true), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, true), "NaN"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, true), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64, true), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, 1, true), "3E0"); - assert_eq!(to_string(f, 3.14, Minus, 1, false), "3e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, 1, false), "+3e0"); - assert_eq!(to_string(f, -3.14, Minus, 2, true), "-3.1E0"); - assert_eq!(to_string(f, -3.14, Minus, 2, false), "-3.1e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, 2, false), "-3.1e0"); - assert_eq!(to_string(f, 3.14, Minus, 3, true), "3.14E0"); - assert_eq!(to_string(f, 3.14, Minus, 3, false), "3.14e0"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3, false), "+3.14e0"); - assert_eq!(to_string(f, -3.14, Minus, 4, true), "-3.140E0"); - assert_eq!(to_string(f, -3.14, Minus, 4, false), "-3.140e0"); - assert_eq!(to_string(f, -3.14, MinusPlus, 4, false), "-3.140e0"); - - assert_eq!(to_string(f, 0.195, Minus, 1, false), "2e-1"); - assert_eq!(to_string(f, 0.195, Minus, 1, true), "2E-1"); - assert_eq!(to_string(f, 0.195, MinusPlus, 1, true), "+2E-1"); - assert_eq!(to_string(f, -0.195, Minus, 2, false), "-2.0e-1"); - assert_eq!(to_string(f, -0.195, Minus, 2, true), "-2.0E-1"); - assert_eq!(to_string(f, -0.195, MinusPlus, 2, true), "-2.0E-1"); - assert_eq!(to_string(f, 0.195, Minus, 3, false), "1.95e-1"); - assert_eq!(to_string(f, 0.195, Minus, 3, true), "1.95E-1"); - assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+1.95E-1"); - assert_eq!(to_string(f, -0.195, Minus, 4, false), "-1.950e-1"); - assert_eq!(to_string(f, -0.195, Minus, 4, true), "-1.950E-1"); - assert_eq!(to_string(f, -0.195, MinusPlus, 4, true), "-1.950E-1"); - - assert_eq!(to_string(f, 9.5, Minus, 1, false), "1e1"); - assert_eq!(to_string(f, 9.5, Minus, 2, false), "9.5e0"); - assert_eq!(to_string(f, 9.5, Minus, 3, false), "9.50e0"); - assert_eq!(to_string(f, 9.5, Minus, 30, false), "9.50000000000000000000000000000e0"); - - assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "1e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 2, false), "1.0e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 15, false), "1.00000000000000e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 16, false), "1.000000000000000e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 17, false), "1.0000000000000001e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 18, false), "1.00000000000000009e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 19, false), "1.000000000000000091e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 20, false), "1.0000000000000000906e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 21, false), "1.00000000000000009060e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 22, false), "1.000000000000000090597e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 23, false), "1.0000000000000000905970e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 24, false), "1.00000000000000009059697e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 25, false), "1.000000000000000090596966e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 26, false), "1.0000000000000000905969664e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 27, false), "1.00000000000000009059696640e25"); - assert_eq!(to_string(f, 1.0e25, Minus, 30, false), "1.00000000000000009059696640000e25"); - - assert_eq!(to_string(f, 1.0e-6, Minus, 1, false), "1e-6"); - assert_eq!(to_string(f, 1.0e-6, Minus, 2, false), "1.0e-6"); - assert_eq!(to_string(f, 1.0e-6, Minus, 16, false), "1.000000000000000e-6"); - assert_eq!(to_string(f, 1.0e-6, Minus, 17, false), "9.9999999999999995e-7"); - assert_eq!(to_string(f, 1.0e-6, Minus, 18, false), "9.99999999999999955e-7"); - assert_eq!(to_string(f, 1.0e-6, Minus, 19, false), "9.999999999999999547e-7"); - assert_eq!(to_string(f, 1.0e-6, Minus, 20, false), "9.9999999999999995475e-7"); - assert_eq!(to_string(f, 1.0e-6, Minus, 30, false), "9.99999999999999954748111825886e-7"); - assert_eq!( - to_string(f, 1.0e-6, Minus, 40, false), - "9.999999999999999547481118258862586856139e-7" - ); - assert_eq!( - to_string(f, 1.0e-6, Minus, 50, false), - "9.9999999999999995474811182588625868561393872369081e-7" - ); - assert_eq!( - to_string(f, 1.0e-6, Minus, 60, false), - "9.99999999999999954748111825886258685613938723690807819366455e-7" - ); - assert_eq!( - to_string(f, 1.0e-6, Minus, 70, false), - "9.999999999999999547481118258862586856139387236908078193664550781250000e-7" - ); - - assert_eq!(to_string(f, f32::MAX, Minus, 1, false), "3e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "3.4e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 4, false), "3.403e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 8, false), "3.4028235e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 16, false), "3.402823466385289e38"); - assert_eq!(to_string(f, f32::MAX, Minus, 32, false), "3.4028234663852885981170418348452e38"); - assert_eq!( - to_string(f, f32::MAX, Minus, 64, false), - "3.402823466385288598117041834845169254400000000000000000000000000e38" - ); - - let minf32 = ldexp_f32(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, 1, false), "1e-45"); - assert_eq!(to_string(f, minf32, Minus, 2, false), "1.4e-45"); - assert_eq!(to_string(f, minf32, Minus, 4, false), "1.401e-45"); - assert_eq!(to_string(f, minf32, Minus, 8, false), "1.4012985e-45"); - assert_eq!(to_string(f, minf32, Minus, 16, false), "1.401298464324817e-45"); - assert_eq!(to_string(f, minf32, Minus, 32, false), "1.4012984643248170709237295832899e-45"); - assert_eq!( - to_string(f, minf32, Minus, 64, false), - "1.401298464324817070923729583289916131280261941876515771757068284e-45" - ); - assert_eq!( - to_string(f, minf32, Minus, 128, false), - "1.401298464324817070923729583289916131280261941876515771757068283\ - 8897910826858606014866381883621215820312500000000000000000000000e-45" - ); - - if cfg!(miri) { - // Miri is too slow - return; - } - - assert_eq!(to_string(f, f64::MAX, Minus, 1, false), "2e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 2, false), "1.8e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 4, false), "1.798e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 8, false), "1.7976931e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 16, false), "1.797693134862316e308"); - assert_eq!(to_string(f, f64::MAX, Minus, 32, false), "1.7976931348623157081452742373170e308"); - assert_eq!( - to_string(f, f64::MAX, Minus, 64, false), - "1.797693134862315708145274237317043567980705675258449965989174768e308" - ); - assert_eq!( - to_string(f, f64::MAX, Minus, 128, false), - "1.797693134862315708145274237317043567980705675258449965989174768\ - 0315726078002853876058955863276687817154045895351438246423432133e308" - ); - assert_eq!( - to_string(f, f64::MAX, Minus, 256, false), - "1.797693134862315708145274237317043567980705675258449965989174768\ - 0315726078002853876058955863276687817154045895351438246423432132\ - 6889464182768467546703537516986049910576551282076245490090389328\ - 9440758685084551339423045832369032229481658085593321233482747978e308" - ); - assert_eq!( - to_string(f, f64::MAX, Minus, 512, false), - "1.797693134862315708145274237317043567980705675258449965989174768\ - 0315726078002853876058955863276687817154045895351438246423432132\ - 6889464182768467546703537516986049910576551282076245490090389328\ - 9440758685084551339423045832369032229481658085593321233482747978\ - 2620414472316873817718091929988125040402618412485836800000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000e308" - ); - - // okay, this is becoming tough. fortunately for us, this is almost the worst case. - let minf64 = ldexp_f64(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, 1, false), "5e-324"); - assert_eq!(to_string(f, minf64, Minus, 2, false), "4.9e-324"); - assert_eq!(to_string(f, minf64, Minus, 4, false), "4.941e-324"); - assert_eq!(to_string(f, minf64, Minus, 8, false), "4.9406565e-324"); - assert_eq!(to_string(f, minf64, Minus, 16, false), "4.940656458412465e-324"); - assert_eq!(to_string(f, minf64, Minus, 32, false), "4.9406564584124654417656879286822e-324"); - assert_eq!( - to_string(f, minf64, Minus, 64, false), - "4.940656458412465441765687928682213723650598026143247644255856825e-324" - ); - assert_eq!( - to_string(f, minf64, Minus, 128, false), - "4.940656458412465441765687928682213723650598026143247644255856825\ - 0067550727020875186529983636163599237979656469544571773092665671e-324" - ); - assert_eq!( - to_string(f, minf64, Minus, 256, false), - "4.940656458412465441765687928682213723650598026143247644255856825\ - 0067550727020875186529983636163599237979656469544571773092665671\ - 0355939796398774796010781878126300713190311404527845817167848982\ - 1036887186360569987307230500063874091535649843873124733972731696e-324" - ); - assert_eq!( - to_string(f, minf64, Minus, 512, false), - "4.940656458412465441765687928682213723650598026143247644255856825\ - 0067550727020875186529983636163599237979656469544571773092665671\ - 0355939796398774796010781878126300713190311404527845817167848982\ - 1036887186360569987307230500063874091535649843873124733972731696\ - 1514003171538539807412623856559117102665855668676818703956031062\ - 4931945271591492455329305456544401127480129709999541931989409080\ - 4165633245247571478690147267801593552386115501348035264934720193\ - 7902681071074917033322268447533357208324319360923828934583680601e-324" - ); - assert_eq!( - to_string(f, minf64, Minus, 1024, false), - "4.940656458412465441765687928682213723650598026143247644255856825\ - 0067550727020875186529983636163599237979656469544571773092665671\ - 0355939796398774796010781878126300713190311404527845817167848982\ - 1036887186360569987307230500063874091535649843873124733972731696\ - 1514003171538539807412623856559117102665855668676818703956031062\ - 4931945271591492455329305456544401127480129709999541931989409080\ - 4165633245247571478690147267801593552386115501348035264934720193\ - 7902681071074917033322268447533357208324319360923828934583680601\ - 0601150616980975307834227731832924790498252473077637592724787465\ - 6084778203734469699533647017972677717585125660551199131504891101\ - 4510378627381672509558373897335989936648099411642057026370902792\ - 4276754456522908753868250641971826553344726562500000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000e-324" - ); - - // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>79999}e0", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("1.{:0>79999}e1", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>79999}e0", "")); - assert_eq!( - to_string(f, 1.0e-1, Minus, 80000, false), - format!( - "1.000000000000000055511151231257827021181583404541015625{:0>79945}\ - e-1", - "" - ) - ); - assert_eq!( - to_string(f, 1.0e-20, Minus, 80000, false), - format!( - "9.999999999999999451532714542095716517295037027873924471077157760\ - 66783064379706047475337982177734375{:0>79901}e-21", - "" - ) - ); -} - -pub fn to_exact_fixed_str_test(mut f_: F) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), -{ - use core::num::flt2dec::Sign::*; - - fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String - where - T: DecodableFloat, - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), - { - to_string_with_parts(|buf, parts| { - to_exact_fixed_str(|d, b, l| f(d, b, l), v, sign, frac_digits, buf, parts) - }) - } - - let f = &mut f_; - - assert_eq!(to_string(f, 0.0, Minus, 0), "0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); - assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); - - assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 64), "+inf"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, 0), "3"); - assert_eq!(to_string(f, 3.14, Minus, 0), "3"); - assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3"); - assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); - assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); - assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3"); - assert_eq!(to_string(f, 3.14, Minus, 1), "3.1"); - assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); - assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); - - assert_eq!(to_string(f, 0.195, Minus, 0), "0"); - assert_eq!(to_string(f, 0.195, MinusPlus, 0), "+0"); - assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); - assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); - assert_eq!(to_string(f, -0.195, MinusPlus, 0), "-0"); - assert_eq!(to_string(f, 0.195, Minus, 1), "0.2"); - assert_eq!(to_string(f, 0.195, Minus, 2), "0.20"); - assert_eq!(to_string(f, 0.195, MinusPlus, 4), "+0.1950"); - assert_eq!(to_string(f, -0.195, Minus, 5), "-0.19500"); - assert_eq!(to_string(f, -0.195, Minus, 6), "-0.195000"); - assert_eq!(to_string(f, -0.195, MinusPlus, 8), "-0.19500000"); - - assert_eq!(to_string(f, 999.5, Minus, 0), "1000"); - assert_eq!(to_string(f, 999.5, Minus, 1), "999.5"); - assert_eq!(to_string(f, 999.5, Minus, 2), "999.50"); - assert_eq!(to_string(f, 999.5, Minus, 3), "999.500"); - assert_eq!(to_string(f, 999.5, Minus, 30), "999.500000000000000000000000000000"); - - assert_eq!(to_string(f, 0.5, Minus, 0), "0"); - assert_eq!(to_string(f, 0.5, Minus, 1), "0.5"); - assert_eq!(to_string(f, 0.5, Minus, 2), "0.50"); - assert_eq!(to_string(f, 0.5, Minus, 3), "0.500"); - - assert_eq!(to_string(f, 0.95, Minus, 0), "1"); - assert_eq!(to_string(f, 0.95, Minus, 1), "0.9"); // because it really is less than 0.95 - assert_eq!(to_string(f, 0.95, Minus, 2), "0.95"); - assert_eq!(to_string(f, 0.95, Minus, 3), "0.950"); - assert_eq!(to_string(f, 0.95, Minus, 10), "0.9500000000"); - assert_eq!(to_string(f, 0.95, Minus, 30), "0.949999999999999955591079014994"); - - assert_eq!(to_string(f, 0.095, Minus, 0), "0"); - assert_eq!(to_string(f, 0.095, Minus, 1), "0.1"); - assert_eq!(to_string(f, 0.095, Minus, 2), "0.10"); - assert_eq!(to_string(f, 0.095, Minus, 3), "0.095"); - assert_eq!(to_string(f, 0.095, Minus, 4), "0.0950"); - assert_eq!(to_string(f, 0.095, Minus, 10), "0.0950000000"); - assert_eq!(to_string(f, 0.095, Minus, 30), "0.095000000000000001110223024625"); - - assert_eq!(to_string(f, 0.0095, Minus, 0), "0"); - assert_eq!(to_string(f, 0.0095, Minus, 1), "0.0"); - assert_eq!(to_string(f, 0.0095, Minus, 2), "0.01"); - assert_eq!(to_string(f, 0.0095, Minus, 3), "0.009"); // really is less than 0.0095 - assert_eq!(to_string(f, 0.0095, Minus, 4), "0.0095"); - assert_eq!(to_string(f, 0.0095, Minus, 5), "0.00950"); - assert_eq!(to_string(f, 0.0095, Minus, 10), "0.0095000000"); - assert_eq!(to_string(f, 0.0095, Minus, 30), "0.009499999999999999764077607267"); - - assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0"); - assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000"); - assert_eq!(to_string(f, 7.5e-11, Minus, 10), "0.0000000001"); - assert_eq!(to_string(f, 7.5e-11, Minus, 11), "0.00000000007"); // ditto - assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750"); - assert_eq!(to_string(f, 7.5e-11, Minus, 20), "0.00000000007500000000"); - assert_eq!(to_string(f, 7.5e-11, Minus, 30), "0.000000000074999999999999999501"); - - assert_eq!(to_string(f, 1.0e25, Minus, 0), "10000000000000000905969664"); - assert_eq!(to_string(f, 1.0e25, Minus, 1), "10000000000000000905969664.0"); - assert_eq!(to_string(f, 1.0e25, Minus, 3), "10000000000000000905969664.000"); - - assert_eq!(to_string(f, 1.0e-6, Minus, 0), "0"); - assert_eq!(to_string(f, 1.0e-6, Minus, 3), "0.000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 6), "0.000001"); - assert_eq!(to_string(f, 1.0e-6, Minus, 9), "0.000001000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 12), "0.000001000000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 22), "0.0000010000000000000000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 23), "0.00000099999999999999995"); - assert_eq!(to_string(f, 1.0e-6, Minus, 24), "0.000000999999999999999955"); - assert_eq!(to_string(f, 1.0e-6, Minus, 25), "0.0000009999999999999999547"); - assert_eq!(to_string(f, 1.0e-6, Minus, 35), "0.00000099999999999999995474811182589"); - assert_eq!(to_string(f, 1.0e-6, Minus, 45), "0.000000999999999999999954748111825886258685614"); - assert_eq!( - to_string(f, 1.0e-6, Minus, 55), - "0.0000009999999999999999547481118258862586856139387236908" - ); - assert_eq!( - to_string(f, 1.0e-6, Minus, 65), - "0.00000099999999999999995474811182588625868561393872369080781936646" - ); - assert_eq!( - to_string(f, 1.0e-6, Minus, 75), - "0.000000999999999999999954748111825886258685613938723690807819366455078125000" - ); - - assert_eq!(to_string(f, f32::MAX, Minus, 0), "340282346638528859811704183484516925440"); - assert_eq!(to_string(f, f32::MAX, Minus, 1), "340282346638528859811704183484516925440.0"); - assert_eq!(to_string(f, f32::MAX, Minus, 2), "340282346638528859811704183484516925440.00"); - - if cfg!(miri) { - // Miri is too slow - return; - } - - let minf32 = ldexp_f32(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, 0), "0"); - assert_eq!(to_string(f, minf32, Minus, 1), "0.0"); - assert_eq!(to_string(f, minf32, Minus, 2), "0.00"); - assert_eq!(to_string(f, minf32, Minus, 4), "0.0000"); - assert_eq!(to_string(f, minf32, Minus, 8), "0.00000000"); - assert_eq!(to_string(f, minf32, Minus, 16), "0.0000000000000000"); - assert_eq!(to_string(f, minf32, Minus, 32), "0.00000000000000000000000000000000"); - assert_eq!( - to_string(f, minf32, Minus, 64), - "0.0000000000000000000000000000000000000000000014012984643248170709" - ); - assert_eq!( - to_string(f, minf32, Minus, 128), - "0.0000000000000000000000000000000000000000000014012984643248170709\ - 2372958328991613128026194187651577175706828388979108268586060149" - ); - assert_eq!( - to_string(f, minf32, Minus, 256), - "0.0000000000000000000000000000000000000000000014012984643248170709\ - 2372958328991613128026194187651577175706828388979108268586060148\ - 6638188362121582031250000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000" - ); - - assert_eq!( - to_string(f, f64::MAX, Minus, 0), - "1797693134862315708145274237317043567980705675258449965989174768\ - 0315726078002853876058955863276687817154045895351438246423432132\ - 6889464182768467546703537516986049910576551282076245490090389328\ - 9440758685084551339423045832369032229481658085593321233482747978\ - 26204144723168738177180919299881250404026184124858368" - ); - assert_eq!( - to_string(f, f64::MAX, Minus, 10), - "1797693134862315708145274237317043567980705675258449965989174768\ - 0315726078002853876058955863276687817154045895351438246423432132\ - 6889464182768467546703537516986049910576551282076245490090389328\ - 9440758685084551339423045832369032229481658085593321233482747978\ - 26204144723168738177180919299881250404026184124858368.0000000000" - ); - - let minf64 = ldexp_f64(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, 0), "0"); - assert_eq!(to_string(f, minf64, Minus, 1), "0.0"); - assert_eq!(to_string(f, minf64, Minus, 10), "0.0000000000"); - assert_eq!( - to_string(f, minf64, Minus, 100), - "0.0000000000000000000000000000000000000000000000000000000000000000\ - 000000000000000000000000000000000000" - ); - assert_eq!( - to_string(f, minf64, Minus, 1000), - "0.0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0004940656458412465441765687928682213723650598026143247644255856\ - 8250067550727020875186529983636163599237979656469544571773092665\ - 6710355939796398774796010781878126300713190311404527845817167848\ - 9821036887186360569987307230500063874091535649843873124733972731\ - 6961514003171538539807412623856559117102665855668676818703956031\ - 0624931945271591492455329305456544401127480129709999541931989409\ - 0804165633245247571478690147267801593552386115501348035264934720\ - 1937902681071074917033322268447533357208324319360923828934583680\ - 6010601150616980975307834227731832924790498252473077637592724787\ - 4656084778203734469699533647017972677717585125660551199131504891\ - 1014510378627381672509558373897335989937" - ); - - // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000), format!("0.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000), format!("10.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000), format!("1.{:0>80000}", "")); - assert_eq!( - to_string(f, 1.0e-1, Minus, 80000), - format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "") - ); - assert_eq!( - to_string(f, 1.0e-20, Minus, 80000), - format!( - "0.0000000000000000000099999999999999994515327145420957165172950370\ - 2787392447107715776066783064379706047475337982177734375{:0>79881}", - "" - ) - ); -} diff --git a/library/core/tests/num/flt2dec/random.rs b/library/core/tests/num/flt2dec/random.rs deleted file mode 100644 index 90042ae03bf..00000000000 --- a/library/core/tests/num/flt2dec/random.rs +++ /dev/null @@ -1,191 +0,0 @@ -#![cfg(not(target_arch = "wasm32"))] - -use core::num::flt2dec::strategy::grisu::{format_exact_opt, format_shortest_opt}; -use core::num::flt2dec::{DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, decode}; -use std::mem::MaybeUninit; -use std::str; - -use rand::distributions::{Distribution, Uniform}; - -pub fn decode_finite(v: T) -> Decoded { - match decode(v).1 { - FullDecoded::Finite(decoded) => decoded, - full_decoded => panic!("expected finite, got {full_decoded:?} instead"), - } -} - -fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, - G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), - V: FnMut(usize) -> Decoded, -{ - assert!(k <= 1024); - - let mut npassed = 0; // f(x) = Some(g(x)) - let mut nignored = 0; // f(x) = None - - for i in 0..n { - if (i & 0xfffff) == 0 { - println!( - "in progress, {:x}/{:x} (ignored={} passed={} failed={})", - i, - n, - nignored, - npassed, - i - nignored - npassed - ); - } - - let decoded = v(i); - let mut buf1 = [MaybeUninit::new(0); 1024]; - if let Some((buf1, e1)) = f(&decoded, &mut buf1[..k]) { - let mut buf2 = [MaybeUninit::new(0); 1024]; - let (buf2, e2) = g(&decoded, &mut buf2[..k]); - if e1 == e2 && buf1 == buf2 { - npassed += 1; - } else { - println!( - "equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", - i, - n, - decoded, - str::from_utf8(buf1).unwrap(), - e1, - str::from_utf8(buf2).unwrap(), - e2 - ); - } - } else { - nignored += 1; - } - } - println!( - "{}({}): done, ignored={} passed={} failed={}", - func, - k, - nignored, - npassed, - n - nignored - npassed - ); - assert!( - nignored + npassed == n, - "{}({}): {} out of {} values returns an incorrect value!", - func, - k, - n - nignored - npassed, - n - ); - (npassed, nignored) -} - -pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, - G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), -{ - let mut rng = crate::test_rng(); - let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000); - iterate("f32_random_equivalence_test", k, n, f, g, |_| { - let x = f32::from_bits(f32_range.sample(&mut rng)); - decode_finite(x) - }); -} - -pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, - G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), -{ - let mut rng = crate::test_rng(); - let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); - iterate("f64_random_equivalence_test", k, n, f, g, |_| { - let x = f64::from_bits(f64_range.sample(&mut rng)); - decode_finite(x) - }); -} - -pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) -where - F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, - G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), -{ - // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, - // so why not simply testing all of them? - // - // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), - // but with `-C opt-level=3 -C lto` this only takes about an hour or so. - - // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e., all finite ranges - let (npassed, nignored) = - iterate("f32_exhaustive_equivalence_test", k, 0x7f7f_ffff, f, g, |i: usize| { - let x = f32::from_bits(i as u32 + 1); - decode_finite(x) - }); - assert_eq!((npassed, nignored), (2121451881, 17643158)); -} - -#[test] -fn shortest_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - // Miri is too slow - let n = if cfg!(miri) { 10 } else { 10_000 }; - - f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n); - f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n); -} - -#[test] -#[ignore] // it is too expensive -fn shortest_f32_exhaustive_equivalence_test() { - // it is hard to directly test the optimality of the output, but we can at least test if - // two different algorithms agree to each other. - // - // this reports the progress and the number of f32 values returned `None`. - // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: - // `done, ignored=17643158 passed=2121451881 failed=0`. - - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); -} - -#[test] -#[ignore] // it is too expensive -fn shortest_f64_hard_random_equivalence_test() { - // this again probably has to use appropriate rustc flags. - - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 100_000_000); -} - -#[test] -fn exact_f32_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; - // Miri is too slow - let n = if cfg!(miri) { 3 } else { 1_000 }; - - for k in 1..21 { - f32_random_equivalence_test( - |d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), - k, - n, - ); - } -} - -#[test] -fn exact_f64_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; - // Miri is too slow - let n = if cfg!(miri) { 2 } else { 1_000 }; - - for k in 1..21 { - f64_random_equivalence_test( - |d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), - k, - n, - ); - } -} diff --git a/library/core/tests/num/flt2dec/strategy/dragon.rs b/library/core/tests/num/flt2dec/strategy/dragon.rs deleted file mode 100644 index be25fee3f6c..00000000000 --- a/library/core/tests/num/flt2dec/strategy/dragon.rs +++ /dev/null @@ -1,64 +0,0 @@ -use core::num::bignum::Big32x40 as Big; -use core::num::flt2dec::strategy::dragon::*; - -use super::super::*; - -#[test] -fn test_mul_pow10() { - let mut prevpow10 = Big::from_small(1); - for i in 1..340 { - let mut curpow10 = Big::from_small(1); - mul_pow10(&mut curpow10, i); - assert_eq!(curpow10, *prevpow10.clone().mul_small(10)); - prevpow10 = curpow10; - } -} - -#[test] -fn shortest_sanity_test() { - f64_shortest_sanity_test(format_shortest); - f32_shortest_sanity_test(format_shortest); - more_shortest_sanity_test(format_shortest); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn exact_sanity_test() { - // This test ends up running what I can only assume is some corner-ish case - // of the `exp2` library function, defined in whatever C runtime we're - // using. In VS 2013 this function apparently had a bug as this test fails - // when linked, but with VS 2015 the bug appears fixed as the test runs just - // fine. - // - // The bug seems to be a difference in return value of `exp2(-1057)`, where - // in VS 2013 it returns a double with the bit pattern 0x2 and in VS 2015 it - // returns 0x20000. - // - // For now just ignore this test entirely on MSVC as it's tested elsewhere - // anyway and we're not super interested in testing each platform's exp2 - // implementation. - if !cfg!(target_env = "msvc") { - f64_exact_sanity_test(format_exact); - } - f32_exact_sanity_test(format_exact); -} - -#[test] -fn test_to_shortest_str() { - to_shortest_str_test(format_shortest); -} - -#[test] -fn test_to_shortest_exp_str() { - to_shortest_exp_str_test(format_shortest); -} - -#[test] -fn test_to_exact_exp_str() { - to_exact_exp_str_test(format_exact); -} - -#[test] -fn test_to_exact_fixed_str() { - to_exact_fixed_str_test(format_exact); -} diff --git a/library/core/tests/num/flt2dec/strategy/grisu.rs b/library/core/tests/num/flt2dec/strategy/grisu.rs deleted file mode 100644 index 9b2f0453de7..00000000000 --- a/library/core/tests/num/flt2dec/strategy/grisu.rs +++ /dev/null @@ -1,73 +0,0 @@ -use core::num::flt2dec::strategy::grisu::*; - -use super::super::*; - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn test_cached_power() { - assert_eq!(CACHED_POW10.first().unwrap().1, CACHED_POW10_FIRST_E); - assert_eq!(CACHED_POW10.last().unwrap().1, CACHED_POW10_LAST_E); - - for e in -1137..961 { - // full range for f64 - let low = ALPHA - e - 64; - let high = GAMMA - e - 64; - let (_k, cached) = cached_power(low, high); - assert!( - low <= cached.e && cached.e <= high, - "cached_power({}, {}) = {:?} is incorrect", - low, - high, - cached - ); - } -} - -#[test] -fn test_max_pow10_no_more_than() { - let mut prevtenk = 1; - for k in 1..10 { - let tenk = prevtenk * 10; - assert_eq!(max_pow10_no_more_than(tenk - 1), (k - 1, prevtenk)); - assert_eq!(max_pow10_no_more_than(tenk), (k, tenk)); - prevtenk = tenk; - } -} - -#[test] -fn shortest_sanity_test() { - f64_shortest_sanity_test(format_shortest); - f32_shortest_sanity_test(format_shortest); - more_shortest_sanity_test(format_shortest); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn exact_sanity_test() { - // See comments in dragon.rs's exact_sanity_test for why this test is - // ignored on MSVC - if !cfg!(target_env = "msvc") { - f64_exact_sanity_test(format_exact); - } - f32_exact_sanity_test(format_exact); -} - -#[test] -fn test_to_shortest_str() { - to_shortest_str_test(format_shortest); -} - -#[test] -fn test_to_shortest_exp_str() { - to_shortest_exp_str_test(format_shortest); -} - -#[test] -fn test_to_exact_exp_str() { - to_exact_exp_str_test(format_exact); -} - -#[test] -fn test_to_exact_fixed_str() { - to_exact_fixed_str_test(format_exact); -} diff --git a/library/core/tests/num/i128.rs b/library/core/tests/num/i128.rs deleted file mode 100644 index 745fee05164..00000000000 --- a/library/core/tests/num/i128.rs +++ /dev/null @@ -1 +0,0 @@ -int_module!(i128, u128); diff --git a/library/core/tests/num/i16.rs b/library/core/tests/num/i16.rs deleted file mode 100644 index 6acb8371b87..00000000000 --- a/library/core/tests/num/i16.rs +++ /dev/null @@ -1 +0,0 @@ -int_module!(i16, u16); diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs deleted file mode 100644 index 38d5071f71d..00000000000 --- a/library/core/tests/num/i32.rs +++ /dev/null @@ -1,30 +0,0 @@ -int_module!(i32, u32); - -#[test] -fn test_arith_operation() { - let a: isize = 10; - assert_eq!(a * (a - 1), 90); - let i32_a: isize = 10; - assert_eq!(i32_a, 10); - assert_eq!(i32_a - 10, 0); - assert_eq!(i32_a / 10, 1); - assert_eq!(i32_a - 20, -10); - assert_eq!(i32_a << 10, 10240); - assert_eq!(i32_a << 16, 655360); - assert_eq!(i32_a * 16, 160); - assert_eq!(i32_a * i32_a * i32_a, 1000); - assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); - assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); - assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); - let i32_b: isize = 0x10101010; - assert_eq!(i32_b + 1 - 1, i32_b); - assert_eq!(i32_b << 1, i32_b << 1); - assert_eq!(i32_b >> 1, i32_b >> 1); - assert_eq!(i32_b & i32_b << 1, 0); - assert_eq!(i32_b | i32_b << 1, 0x30303030); - let i32_c: isize = 0x10101010; - assert_eq!( - i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), - i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3) - ); -} diff --git a/library/core/tests/num/i64.rs b/library/core/tests/num/i64.rs deleted file mode 100644 index f8dd5f9be7f..00000000000 --- a/library/core/tests/num/i64.rs +++ /dev/null @@ -1 +0,0 @@ -int_module!(i64, u64); diff --git a/library/core/tests/num/i8.rs b/library/core/tests/num/i8.rs deleted file mode 100644 index a10906618c9..00000000000 --- a/library/core/tests/num/i8.rs +++ /dev/null @@ -1 +0,0 @@ -int_module!(i8, u8); diff --git a/library/core/tests/num/ieee754.rs b/library/core/tests/num/ieee754.rs deleted file mode 100644 index b0f6a7545aa..00000000000 --- a/library/core/tests/num/ieee754.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! IEEE 754 floating point compliance tests -//! -//! To understand IEEE 754's requirements on a programming language, one must understand that the -//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any -//! one component. That means the hardware, language, and even libraries are considered part of -//! conforming floating point support in a programming environment. -//! -//! A programming language's duty, accordingly, is: -//! 1. offer access to the hardware where the hardware offers support -//! 2. provide operations that fulfill the remaining requirements of the standard -//! 3. provide the ability to write additional software that can fulfill those requirements -//! -//! This may be fulfilled in any combination that the language sees fit. However, to claim that -//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without -//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined -//! as complete support for at least one specified floating point type as an "arithmetic" and -//! "interchange" format, plus specified type conversions to "external character sequences" and -//! integer types. -//! -//! For our purposes, -//! "interchange format" => f32, f64 -//! "arithmetic format" => f32, f64, and any "soft floats" -//! "external character sequence" => str from any float -//! "integer format" => {i,u}{8,16,32,64,128} -//! -//! None of these tests are against Rust's own implementation. They are only tests against the -//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests. -//! Please consider this carefully when adding, removing, or reorganizing these tests. They are -//! here so that it is clear what tests are required by the standard and what can be changed. - -use ::core::str::FromStr; - -// IEEE 754 for many tests is applied to specific bit patterns. -// These generally are not applicable to NaN, however. -macro_rules! assert_biteq { - ($lhs:expr, $rhs:expr) => { - assert_eq!($lhs.to_bits(), $rhs.to_bits()) - }; -} - -// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts -// of the formatting infrastructure, which makes it ideal for testing here. -macro_rules! roundtrip { - ($f:expr => $t:ty) => { - ($f).to_string().parse::<$t>().unwrap() - }; -} - -macro_rules! assert_floats_roundtrip { - ($f:ident) => { - assert_biteq!(f32::$f, roundtrip!(f32::$f => f32)); - assert_biteq!(f64::$f, roundtrip!(f64::$f => f64)); - }; - ($f:expr) => { - assert_biteq!($f as f32, roundtrip!($f => f32)); - assert_biteq!($f as f64, roundtrip!($f => f64)); - } -} - -macro_rules! assert_floats_bitne { - ($lhs:ident, $rhs:ident) => { - assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits()); - assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits()); - }; - ($lhs:expr, $rhs:expr) => { - assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs)); - assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs)); - }; -} - -// We must preserve signs on all numbers. That includes zero. -// -0 and 0 are == normally, so test bit equality. -#[test] -fn preserve_signed_zero() { - assert_floats_roundtrip!(-0.0); - assert_floats_roundtrip!(0.0); - assert_floats_bitne!(0.0, -0.0); -} - -#[test] -fn preserve_signed_infinity() { - assert_floats_roundtrip!(INFINITY); - assert_floats_roundtrip!(NEG_INFINITY); - assert_floats_bitne!(INFINITY, NEG_INFINITY); -} - -#[test] -fn infinity_to_str() { - assert!(match f32::INFINITY.to_string().to_lowercase().as_str() { - "+infinity" | "infinity" => true, - "+inf" | "inf" => true, - _ => false, - }); - assert!( - match f64::INFINITY.to_string().to_lowercase().as_str() { - "+infinity" | "infinity" => true, - "+inf" | "inf" => true, - _ => false, - }, - "Infinity must write to a string as some casing of inf or infinity, with an optional +." - ); -} - -#[test] -fn neg_infinity_to_str() { - assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() { - "-infinity" | "-inf" => true, - _ => false, - }); - assert!( - match f64::NEG_INFINITY.to_string().to_lowercase().as_str() { - "-infinity" | "-inf" => true, - _ => false, - }, - "Negative Infinity must write to a string as some casing of -inf or -infinity" - ) -} - -#[test] -fn nan_to_str() { - assert!( - match f32::NAN.to_string().to_lowercase().as_str() { - "nan" | "+nan" | "-nan" => true, - _ => false, - }, - "NaNs must write to a string as some casing of nan." - ) -} - -// "+"?("inf"|"infinity") in any case => Infinity -#[test] -fn infinity_from_str() { - assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap()); - assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap()); - assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap()); - assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap()); - // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd - assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap()); -} - -// "-inf"|"-infinity" in any case => Negative Infinity -#[test] -fn neg_infinity_from_str() { - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap()); - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap()); - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap()); - assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap()); -} - -// ("+"|"-"")?"s"?"nan" in any case => qNaN -#[test] -fn qnan_from_str() { - assert!("nan".parse::().unwrap().is_nan()); - assert!("-nan".parse::().unwrap().is_nan()); - assert!("+nan".parse::().unwrap().is_nan()); - assert!("+NAN".parse::().unwrap().is_nan()); - assert!("-NaN".parse::().unwrap().is_nan()); -} diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs deleted file mode 100644 index 60902752dab..00000000000 --- a/library/core/tests/num/int_log.rs +++ /dev/null @@ -1,188 +0,0 @@ -//! Tests for the `Integer::{ilog,log2,log10}` methods. - -#[test] -fn checked_ilog() { - assert_eq!(999u32.checked_ilog(10), Some(2)); - assert_eq!(1000u32.checked_ilog(10), Some(3)); - assert_eq!(555u32.checked_ilog(13), Some(2)); - assert_eq!(63u32.checked_ilog(4), Some(2)); - assert_eq!(64u32.checked_ilog(4), Some(3)); - assert_eq!(10460353203u64.checked_ilog(3), Some(21)); - assert_eq!(10460353202u64.checked_ilog(3), Some(20)); - assert_eq!(147808829414345923316083210206383297601u128.checked_ilog(3), Some(80)); - assert_eq!(147808829414345923316083210206383297600u128.checked_ilog(3), Some(79)); - assert_eq!(22528399544939174411840147874772641u128.checked_ilog(19683), Some(8)); - assert_eq!(22528399544939174411840147874772631i128.checked_ilog(19683), Some(7)); - - assert_eq!(0u8.checked_ilog(4), None); - assert_eq!(0u16.checked_ilog(4), None); - assert_eq!(0i8.checked_ilog(4), None); - assert_eq!(0i16.checked_ilog(4), None); - - #[cfg(not(miri))] // Miri is too slow - for i in i16::MIN..=0 { - assert_eq!(i.checked_ilog(4), None, "checking {i}"); - } - #[cfg(not(miri))] // Miri is too slow - for i in 1..=i16::MAX { - assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32), "checking {i}"); - } - #[cfg(not(miri))] // Miri is too slow - for i in 1..=u16::MAX { - assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32), "checking {i}"); - } -} - -#[test] -fn checked_ilog2() { - assert_eq!(5u32.checked_ilog2(), Some(2)); - assert_eq!(0u64.checked_ilog2(), None); - assert_eq!(128i32.checked_ilog2(), Some(7)); - assert_eq!((-55i16).checked_ilog2(), None); - - assert_eq!(0u8.checked_ilog2(), None); - assert_eq!(0u16.checked_ilog2(), None); - assert_eq!(0i8.checked_ilog2(), None); - assert_eq!(0i16.checked_ilog2(), None); - - assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32)); - assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32)); - assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32)); - - for i in 1..=u8::MAX { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); - } - #[cfg(not(miri))] // Miri is too slow - for i in 1..=u16::MAX { - // Guard against Android's imprecise f32::ilog2 implementation. - if i != 8192 && i != 32768 { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); - } - } - for i in i8::MIN..=0 { - assert_eq!(i.checked_ilog2(), None, "checking {i}"); - } - for i in 1..=i8::MAX { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); - } - #[cfg(not(miri))] // Miri is too slow - for i in i16::MIN..=0 { - assert_eq!(i.checked_ilog2(), None, "checking {i}"); - } - #[cfg(not(miri))] // Miri is too slow - for i in 1..=i16::MAX { - // Guard against Android's imprecise f32::ilog2 implementation. - if i != 8192 { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); - } - } -} - -#[test] -fn checked_ilog10() { - assert_eq!(0u8.checked_ilog10(), None); - assert_eq!(0u16.checked_ilog10(), None); - assert_eq!(0i8.checked_ilog10(), None); - assert_eq!(0i16.checked_ilog10(), None); - - #[cfg(not(miri))] // Miri is too slow - for i in i16::MIN..=0 { - assert_eq!(i.checked_ilog10(), None, "checking {i}"); - } - #[cfg(not(miri))] // Miri is too slow - for i in 1..=i16::MAX { - assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); - } - #[cfg(not(miri))] // Miri is too slow - for i in 1..=u16::MAX { - assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); - } - #[cfg(not(miri))] // Miri is too slow - for i in 1..=100_000u32 { - assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); - } -} - -macro_rules! ilog10_loop { - ($T:ty, $ilog10_max:expr) => { - assert_eq!(<$T>::MAX.ilog10(), $ilog10_max); - for i in 0..=$ilog10_max { - let p = (10 as $T).pow(i as u32); - if p >= 10 { - assert_eq!((p - 9).ilog10(), i - 1); - assert_eq!((p - 1).ilog10(), i - 1); - } - assert_eq!(p.ilog10(), i); - assert_eq!((p + 1).ilog10(), i); - if p >= 10 { - assert_eq!((p + 9).ilog10(), i); - } - - // also check `x.ilog(10)` - if p >= 10 { - assert_eq!((p - 9).ilog(10), i - 1); - assert_eq!((p - 1).ilog(10), i - 1); - } - assert_eq!(p.ilog(10), i); - assert_eq!((p + 1).ilog(10), i); - if p >= 10 { - assert_eq!((p + 9).ilog(10), i); - } - } - }; -} - -#[test] -fn ilog10_u8() { - ilog10_loop! { u8, 2 } -} - -#[test] -fn ilog10_u16() { - ilog10_loop! { u16, 4 } -} - -#[test] -fn ilog10_u32() { - ilog10_loop! { u32, 9 } -} - -#[test] -fn ilog10_u64() { - ilog10_loop! { u64, 19 } -} - -#[test] -fn ilog10_u128() { - ilog10_loop! { u128, 38 } -} - -#[test] -#[should_panic(expected = "argument of integer logarithm must be positive")] -fn ilog2_of_0_panic() { - let _ = 0u32.ilog2(); -} - -#[test] -#[should_panic(expected = "argument of integer logarithm must be positive")] -fn ilog10_of_0_panic() { - let _ = 0u32.ilog10(); -} - -#[test] -#[should_panic(expected = "argument of integer logarithm must be positive")] -fn ilog3_of_0_panic() { - let _ = 0u32.ilog(3); -} - -#[test] -#[should_panic(expected = "base of integer logarithm must be at least 2")] -fn ilog0_of_1_panic() { - let _ = 1u32.ilog(0); -} - -#[test] -#[should_panic(expected = "base of integer logarithm must be at least 2")] -fn ilog1_of_1_panic() { - let _ = 1u32.ilog(1); -} diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs deleted file mode 100644 index f13b836378b..00000000000 --- a/library/core/tests/num/int_macros.rs +++ /dev/null @@ -1,482 +0,0 @@ -macro_rules! int_module { - ($T:ident, $U:ident) => { - use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; - use core::$T::*; - - const UMAX: $U = $U::MAX; - - use crate::num; - - #[test] - fn test_overflows() { - assert!(MAX > 0); - assert!(MIN <= 0); - assert_eq!(MIN + MAX + 1, 0); - } - - #[test] - fn test_num() { - num::test_num(10 as $T, 2 as $T); - } - - #[test] - fn test_bitwise_operators() { - assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T)); - assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(0b1010 as $T)); - assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(0b1010 as $T)); - assert_eq!(0b1110 as $T, (0b0111 as $T).shl(1)); - assert_eq!(0b0111 as $T, (0b1110 as $T).shr(1)); - assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not()); - } - - test_runtime_and_compiletime! { - - fn test_rem_euclid() { - assert_eq_const_safe!((-1 as $T).rem_euclid(MIN), MAX); - } - - fn test_abs() { - assert_eq_const_safe!((1 as $T).abs(), 1 as $T); - assert_eq_const_safe!((0 as $T).abs(), 0 as $T); - assert_eq_const_safe!((-1 as $T).abs(), 1 as $T); - } - - fn test_signum() { - assert_eq_const_safe!((1 as $T).signum(), 1 as $T); - assert_eq_const_safe!((0 as $T).signum(), 0 as $T); - assert_eq_const_safe!((-0 as $T).signum(), 0 as $T); - assert_eq_const_safe!((-1 as $T).signum(), -1 as $T); - } - - fn test_is_positive() { - assert!((1 as $T).is_positive()); - assert!(!(0 as $T).is_positive()); - assert!(!(-0 as $T).is_positive()); - assert!(!(-1 as $T).is_positive()); - } - - fn test_is_negative() { - assert!(!(1 as $T).is_negative()); - assert!(!(0 as $T).is_negative()); - assert!(!(-0 as $T).is_negative()); - assert!((-1 as $T).is_negative()); - } - } - - const A: $T = 0b0101100; - const B: $T = 0b0100001; - const C: $T = 0b1111001; - - const _0: $T = 0; - const _1: $T = !0; - - test_runtime_and_compiletime! { - fn test_count_ones() { - assert_eq_const_safe!(A.count_ones(), 3); - assert_eq_const_safe!(B.count_ones(), 2); - assert_eq_const_safe!(C.count_ones(), 5); - } - - fn test_count_zeros() { - assert_eq_const_safe!(A.count_zeros(), $T::BITS - 3); - assert_eq_const_safe!(B.count_zeros(), $T::BITS - 2); - assert_eq_const_safe!(C.count_zeros(), $T::BITS - 5); - } - - fn test_leading_trailing_ones() { - const A: $T = 0b0101_1111; - assert_eq_const_safe!(A.trailing_ones(), 5); - assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); - - assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); - - assert_eq_const_safe!(_1.leading_ones(), $T::BITS); - assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); - - assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); - assert_eq_const_safe!(MAX.leading_ones(), 0); - - assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); - assert_eq_const_safe!(MAX.trailing_ones(), $T::BITS - 1); - - assert_eq_const_safe!(_0.leading_ones(), 0); - assert_eq_const_safe!(_0.trailing_ones(), 0); - - const X: $T = 0b0010_1100; - assert_eq_const_safe!(X.leading_ones(), 0); - assert_eq_const_safe!(X.trailing_ones(), 0); - } - - fn test_rotate() { - assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); - assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); - assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); - - // Rotating these should make no difference - // - // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behavior. See #10183. - assert_eq_const_safe!(_0.rotate_left(124), _0); - assert_eq_const_safe!(_1.rotate_left(124), _1); - assert_eq_const_safe!(_0.rotate_right(124), _0); - assert_eq_const_safe!(_1.rotate_right(124), _1); - - // Rotating by 0 should have no effect - assert_eq_const_safe!(A.rotate_left(0), A); - assert_eq_const_safe!(B.rotate_left(0), B); - assert_eq_const_safe!(C.rotate_left(0), C); - // Rotating by a multiple of word size should also have no effect - assert_eq_const_safe!(A.rotate_left(128), A); - assert_eq_const_safe!(B.rotate_left(128), B); - assert_eq_const_safe!(C.rotate_left(128), C); - } - - fn test_swap_bytes() { - assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); - assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); - assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); - - // Swapping these should make no difference - assert_eq_const_safe!(_0.swap_bytes(), _0); - assert_eq_const_safe!(_1.swap_bytes(), _1); - } - - fn test_le() { - assert_eq_const_safe!($T::from_le(A.to_le()), A); - assert_eq_const_safe!($T::from_le(B.to_le()), B); - assert_eq_const_safe!($T::from_le(C.to_le()), C); - assert_eq_const_safe!($T::from_le(_0), _0); - assert_eq_const_safe!($T::from_le(_1), _1); - assert_eq_const_safe!(_0.to_le(), _0); - assert_eq_const_safe!(_1.to_le(), _1); - } - - fn test_be() { - assert_eq_const_safe!($T::from_be(A.to_be()), A); - assert_eq_const_safe!($T::from_be(B.to_be()), B); - assert_eq_const_safe!($T::from_be(C.to_be()), C); - assert_eq_const_safe!($T::from_be(_0), _0); - assert_eq_const_safe!($T::from_be(_1), _1); - assert_eq_const_safe!(_0.to_be(), _0); - assert_eq_const_safe!(_1.to_be(), _1); - } - - fn test_signed_checked_div() { - assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); - assert_eq_const_safe!((5 as $T).checked_div(0), None); - assert_eq_const_safe!(isize::MIN.checked_div(-1), None); - } - - fn test_saturating_abs() { - assert_eq_const_safe!((0 as $T).saturating_abs(), 0); - assert_eq_const_safe!((123 as $T).saturating_abs(), 123); - assert_eq_const_safe!((-123 as $T).saturating_abs(), 123); - assert_eq_const_safe!((MAX - 2).saturating_abs(), MAX - 2); - assert_eq_const_safe!((MAX - 1).saturating_abs(), MAX - 1); - assert_eq_const_safe!(MAX.saturating_abs(), MAX); - assert_eq_const_safe!((MIN + 2).saturating_abs(), MAX - 1); - assert_eq_const_safe!((MIN + 1).saturating_abs(), MAX); - assert_eq_const_safe!(MIN.saturating_abs(), MAX); - } - - fn test_saturating_neg() { - assert_eq_const_safe!((0 as $T).saturating_neg(), 0); - assert_eq_const_safe!((123 as $T).saturating_neg(), -123); - assert_eq_const_safe!((-123 as $T).saturating_neg(), 123); - assert_eq_const_safe!((MAX - 2).saturating_neg(), MIN + 3); - assert_eq_const_safe!((MAX - 1).saturating_neg(), MIN + 2); - assert_eq_const_safe!(MAX.saturating_neg(), MIN + 1); - assert_eq_const_safe!((MIN + 2).saturating_neg(), MAX - 1); - assert_eq_const_safe!((MIN + 1).saturating_neg(), MAX); - assert_eq_const_safe!(MIN.saturating_neg(), MAX); - } - } - - #[test] - fn test_from_str() { - fn from_str(t: &str) -> Option { - std::str::FromStr::from_str(t).ok() - } - assert_eq!(from_str::<$T>("0"), Some(0 as $T)); - assert_eq!(from_str::<$T>("3"), Some(3 as $T)); - assert_eq!(from_str::<$T>("10"), Some(10 as $T)); - assert_eq!(from_str::("123456789"), Some(123456789 as i32)); - assert_eq!(from_str::<$T>("00100"), Some(100 as $T)); - - assert_eq!(from_str::<$T>("-1"), Some(-1 as $T)); - assert_eq!(from_str::<$T>("-3"), Some(-3 as $T)); - assert_eq!(from_str::<$T>("-10"), Some(-10 as $T)); - assert_eq!(from_str::("-123456789"), Some(-123456789 as i32)); - assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T)); - - assert_eq!(from_str::<$T>(""), None); - assert_eq!(from_str::<$T>(" "), None); - assert_eq!(from_str::<$T>("x"), None); - } - - test_runtime_and_compiletime! { - fn test_from_str_radix() { - assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq_const_safe!(i32::from_str_radix("123", 16), Ok(291 as i32)); - assert_eq_const_safe!(i32::from_str_radix("ffff", 16), Ok(65535 as i32)); - assert_eq_const_safe!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32)); - assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); - assert_eq_const_safe!($T::from_str_radix("Z", 36), Ok(35 as $T)); - - assert_eq_const_safe!($T::from_str_radix("-123", 10), Ok(-123 as $T)); - assert_eq_const_safe!($T::from_str_radix("-1001", 2), Ok(-9 as $T)); - assert_eq_const_safe!($T::from_str_radix("-123", 8), Ok(-83 as $T)); - assert_eq_const_safe!(i32::from_str_radix("-123", 16), Ok(-291 as i32)); - assert_eq_const_safe!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32)); - assert_eq_const_safe!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); - assert_eq_const_safe!($T::from_str_radix("-z", 36), Ok(-35 as $T)); - assert_eq_const_safe!($T::from_str_radix("-Z", 36), Ok(-35 as $T)); - - assert!($T::from_str_radix("Z", 35).is_err()); - assert!($T::from_str_radix("-9", 2).is_err()); - assert!($T::from_str_radix("10_0", 10).is_err()); - assert!(u32::from_str_radix("-9", 10).is_err()); - } - - fn test_pow() { - { - const R: $T = 2; - assert_eq_const_safe!(R.pow(2), 4 as $T); - assert_eq_const_safe!(R.pow(0), 1 as $T); - assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); - assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); - assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); - assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); - assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); - assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); - assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); - } - - { - const R: $T = MAX; - // use `^` to represent .pow() with no overflow. - // if itest::MAX == 2^j-1, then itest is a `j` bit int, - // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, - // thussaturating_pow the overflowing result is exactly 1. - assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), None); - assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); - assert_eq_const_safe!(R.saturating_pow(2), MAX); - } - - { - // test for negative exponent. - const R: $T = -2; - assert_eq_const_safe!(R.pow(2), 4 as $T); - assert_eq_const_safe!(R.pow(3), -8 as $T); - assert_eq_const_safe!(R.pow(0), 1 as $T); - assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); - assert_eq_const_safe!(R.wrapping_pow(3), -8 as $T); - assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); - assert_eq_const_safe!(R.checked_pow(3), Some(-8 as $T)); - assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); - assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); - assert_eq_const_safe!(R.overflowing_pow(3), (-8 as $T, false)); - assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); - assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); - assert_eq_const_safe!(R.saturating_pow(3), -8 as $T); - assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); - } - } - - fn test_div_floor() { - const A: $T = 8; - const B: $T = 3; - assert_eq_const_safe!(A.div_floor(B), 2); - assert_eq_const_safe!(A.div_floor(-B), -3); - assert_eq_const_safe!((-A).div_floor(B), -3); - assert_eq_const_safe!((-A).div_floor(-B), 2); - } - - fn test_div_ceil() { - const A: $T = 8; - const B: $T = 3; - assert_eq_const_safe!(A.div_ceil(B), 3); - assert_eq_const_safe!(A.div_ceil(-B), -2); - assert_eq_const_safe!((-A).div_ceil(B), -2); - assert_eq_const_safe!((-A).div_ceil(-B), 3); - } - - fn test_next_multiple_of() { - assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); - assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); - assert_eq_const_safe!((16 as $T).next_multiple_of(-8), 16); - assert_eq_const_safe!((23 as $T).next_multiple_of(-8), 16); - assert_eq_const_safe!((-16 as $T).next_multiple_of(8), -16); - assert_eq_const_safe!((-23 as $T).next_multiple_of(8), -16); - assert_eq_const_safe!((-16 as $T).next_multiple_of(-8), -16); - assert_eq_const_safe!((-23 as $T).next_multiple_of(-8), -24); - assert_eq_const_safe!(MIN.next_multiple_of(-1), MIN); - } - - fn test_checked_next_multiple_of() { - assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); - assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); - assert_eq_const_safe!((16 as $T).checked_next_multiple_of(-8), Some(16)); - assert_eq_const_safe!((23 as $T).checked_next_multiple_of(-8), Some(16)); - assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(8), Some(-16)); - assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(8), Some(-16)); - assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(-8), Some(-16)); - assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(-8), Some(-24)); - assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); - assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); - assert_eq_const_safe!(MIN.checked_next_multiple_of(-3), None); - assert_eq_const_safe!(MIN.checked_next_multiple_of(-1), Some(MIN)); - } - - fn test_carrying_add() { - assert_eq_const_safe!(MAX.carrying_add(1, false), (MIN, true)); - assert_eq_const_safe!(MAX.carrying_add(0, true), (MIN, true)); - assert_eq_const_safe!(MAX.carrying_add(1, true), (MIN + 1, true)); - assert_eq_const_safe!(MAX.carrying_add(-1, false), (MAX - 1, false)); - assert_eq_const_safe!(MAX.carrying_add(-1, true), (MAX, false)); // no intermediate overflow - assert_eq_const_safe!(MIN.carrying_add(-1, false), (MAX, true)); - assert_eq_const_safe!(MIN.carrying_add(-1, true), (MIN, false)); // no intermediate overflow - assert_eq_const_safe!((0 as $T).carrying_add(MAX, true), (MIN, true)); - assert_eq_const_safe!((0 as $T).carrying_add(MIN, true), (MIN + 1, false)); - } - - fn test_borrowing_sub() { - assert_eq_const_safe!(MIN.borrowing_sub(1, false), (MAX, true)); - assert_eq_const_safe!(MIN.borrowing_sub(0, true), (MAX, true)); - assert_eq_const_safe!(MIN.borrowing_sub(1, true), (MAX - 1, true)); - assert_eq_const_safe!(MIN.borrowing_sub(-1, false), (MIN + 1, false)); - assert_eq_const_safe!(MIN.borrowing_sub(-1, true), (MIN, false)); // no intermediate overflow - assert_eq_const_safe!(MAX.borrowing_sub(-1, false), (MIN, true)); - assert_eq_const_safe!(MAX.borrowing_sub(-1, true), (MAX, false)); // no intermediate overflow - assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, false), (MIN, true)); - assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, true), (MAX, false)); - } - - fn test_widening_mul() { - assert_eq_const_safe!(MAX.widening_mul(MAX), (1, MAX / 2)); - assert_eq_const_safe!(MIN.widening_mul(MAX), (MIN as $U, MIN / 2)); - assert_eq_const_safe!(MIN.widening_mul(MIN), (0, MAX / 2 + 1)); - } - - fn test_carrying_mul() { - assert_eq_const_safe!(MAX.carrying_mul(MAX, 0), (1, MAX / 2)); - assert_eq_const_safe!( - MAX.carrying_mul(MAX, MAX), - (UMAX / 2 + 1, MAX / 2) - ); - assert_eq_const_safe!( - MAX.carrying_mul(MAX, MIN), - (UMAX / 2 + 2, MAX / 2 - 1) - ); - assert_eq_const_safe!(MIN.carrying_mul(MAX, 0), (MIN as $U, MIN / 2)); - assert_eq_const_safe!(MIN.carrying_mul(MAX, MAX), (UMAX, MIN / 2)); - assert_eq_const_safe!(MIN.carrying_mul(MAX, MIN), (0, MIN / 2)); - assert_eq_const_safe!(MIN.carrying_mul(MIN, 0), (0, MAX / 2 + 1)); - assert_eq_const_safe!( - MIN.carrying_mul(MIN, MAX), - (UMAX / 2, MAX / 2 + 1) - ); - assert_eq_const_safe!( - MIN.carrying_mul(MIN, MIN), - (UMAX / 2 + 1, MAX / 2) - ); - } - - fn test_carrying_mul_add() { - assert_eq_const_safe!(MAX.carrying_mul_add(MAX, 0, 0), (1, MAX / 2)); - assert_eq_const_safe!( - MAX.carrying_mul_add(MAX, MAX, 0), - (UMAX / 2 + 1, MAX / 2) - ); - assert_eq_const_safe!( - MAX.carrying_mul_add(MAX, MIN, 0), - (UMAX / 2 + 2, MAX / 2 - 1) - ); - assert_eq_const_safe!( - MAX.carrying_mul_add(MAX, MAX, MAX), - (UMAX, MAX / 2) - ); - assert_eq_const_safe!( - MAX.carrying_mul_add(MAX, MAX, MIN), - (0, MAX / 2) - ); - assert_eq_const_safe!( - MAX.carrying_mul_add(MAX, MIN, MIN), - (1, MAX / 2 - 1) - ); - assert_eq_const_safe!( - MIN.carrying_mul_add(MAX, 0, 0), - (MIN as $U, MIN / 2) - ); - assert_eq_const_safe!( - MIN.carrying_mul_add(MAX, MAX, 0), - (UMAX, MIN / 2) - ); - assert_eq_const_safe!(MIN.carrying_mul_add(MAX, MIN, 0), (0, MIN / 2)); - assert_eq_const_safe!( - MIN.carrying_mul_add(MAX, MAX, MAX), - (UMAX / 2 - 1, MIN / 2 + 1) - ); - assert_eq_const_safe!( - MIN.carrying_mul_add(MAX, MAX, MIN), - (UMAX / 2, MIN / 2) - ); - assert_eq_const_safe!( - MIN.carrying_mul_add(MAX, MIN, MIN), - (UMAX / 2 + 1, MIN / 2 - 1) - ); - assert_eq_const_safe!(MIN.carrying_mul_add(MIN, 0, 0), (0, MAX / 2 + 1)); - assert_eq_const_safe!( - MIN.carrying_mul_add(MIN, MAX, 0), - (UMAX / 2, MAX / 2 + 1) - ); - assert_eq_const_safe!( - MIN.carrying_mul_add(MIN, MIN, 0), - (UMAX / 2 + 1, MAX / 2) - ); - assert_eq_const_safe!( - MIN.carrying_mul_add(MIN, MAX, MAX), - (UMAX - 1, MAX / 2 + 1) - ); - assert_eq_const_safe!( - MIN.carrying_mul_add(MIN, MAX, MIN), - (UMAX, MAX / 2) - ); - assert_eq_const_safe!( - MIN.carrying_mul_add(MIN, MIN, MIN), - (0, MAX / 2) - ); - } - - fn test_midpoint() { - assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); - assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); - - assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); - assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); - assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); - assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); - - assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); - assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); - assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); - assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); - - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), 0); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), 0); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); - - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); - } - } - }; -} diff --git a/library/core/tests/num/int_sqrt.rs b/library/core/tests/num/int_sqrt.rs deleted file mode 100644 index d68db0787d2..00000000000 --- a/library/core/tests/num/int_sqrt.rs +++ /dev/null @@ -1,248 +0,0 @@ -macro_rules! tests { - ($isqrt_consistency_check_fn_macro:ident : $($T:ident)+) => { - $( - mod $T { - $isqrt_consistency_check_fn_macro!($T); - - // Check that the following produce the correct values from - // `isqrt`: - // - // * the first and last 128 nonnegative values - // * powers of two, minus one - // * powers of two - // - // For signed types, check that `checked_isqrt` and `isqrt` - // either produce the same numeric value or respectively - // produce `None` and a panic. Make sure to do a consistency - // check for `<$T>::MIN` as well, as no nonnegative values - // negate to it. - // - // For unsigned types check that `isqrt` produces the same - // numeric value for `$T` and `NonZero<$T>`. - #[test] - fn isqrt() { - isqrt_consistency_check(<$T>::MIN); - - for n in (0..=127) - .chain(<$T>::MAX - 127..=<$T>::MAX) - .chain((0..<$T>::MAX.count_ones()).map(|exponent| (1 << exponent) - 1)) - .chain((0..<$T>::MAX.count_ones()).map(|exponent| 1 << exponent)) - { - isqrt_consistency_check(n); - - let isqrt_n = n.isqrt(); - assert!( - isqrt_n - .checked_mul(isqrt_n) - .map(|isqrt_n_squared| isqrt_n_squared <= n) - .unwrap_or(false), - "`{n}.isqrt()` should be lower than {isqrt_n}." - ); - assert!( - (isqrt_n + 1) - .checked_mul(isqrt_n + 1) - .map(|isqrt_n_plus_1_squared| n < isqrt_n_plus_1_squared) - .unwrap_or(true), - "`{n}.isqrt()` should be higher than {isqrt_n})." - ); - } - } - - // Check the square roots of: - // - // * the first 1,024 perfect squares - // * halfway between each of the first 1,024 perfect squares - // and the next perfect square - // * the next perfect square after the each of the first 1,024 - // perfect squares, minus one - // * the last 1,024 perfect squares - // * the last 1,024 perfect squares, minus one - // * halfway between each of the last 1,024 perfect squares - // and the previous perfect square - #[test] - // Skip this test on Miri, as it takes too long to run. - #[cfg(not(miri))] - fn isqrt_extended() { - // The correct value is worked out by using the fact that - // the nth nonzero perfect square is the sum of the first n - // odd numbers: - // - // 1 = 1 - // 4 = 1 + 3 - // 9 = 1 + 3 + 5 - // 16 = 1 + 3 + 5 + 7 - // - // Note also that the last odd number added in is two times - // the square root of the previous perfect square, plus - // one: - // - // 1 = 2*0 + 1 - // 3 = 2*1 + 1 - // 5 = 2*2 + 1 - // 7 = 2*3 + 1 - // - // That means we can add the square root of this perfect - // square once to get about halfway to the next perfect - // square, then we can add the square root of this perfect - // square again to get to the next perfect square, minus - // one, then we can add one to get to the next perfect - // square. - // - // This allows us to, for each of the first 1,024 perfect - // squares, test that the square roots of the following are - // all correct and equal to each other: - // - // * the current perfect square - // * about halfway to the next perfect square - // * the next perfect square, minus one - let mut n: $T = 0; - for sqrt_n in 0..1_024.min((1_u128 << (<$T>::MAX.count_ones()/2)) - 1) as $T { - isqrt_consistency_check(n); - assert_eq!( - n.isqrt(), - sqrt_n, - "`{sqrt_n}.pow(2).isqrt()` should be {sqrt_n}." - ); - - n += sqrt_n; - isqrt_consistency_check(n); - assert_eq!( - n.isqrt(), - sqrt_n, - "{n} is about halfway between `{sqrt_n}.pow(2)` and `{}.pow(2)`, so `{n}.isqrt()` should be {sqrt_n}.", - sqrt_n + 1 - ); - - n += sqrt_n; - isqrt_consistency_check(n); - assert_eq!( - n.isqrt(), - sqrt_n, - "`({}.pow(2) - 1).isqrt()` should be {sqrt_n}.", - sqrt_n + 1 - ); - - n += 1; - } - - // Similarly, for each of the last 1,024 perfect squares, - // check: - // - // * the current perfect square - // * the current perfect square, minus one - // * about halfway to the previous perfect square - // - // `MAX`'s `isqrt` return value is verified in the `isqrt` - // test function above. - let maximum_sqrt = <$T>::MAX.isqrt(); - let mut n = maximum_sqrt * maximum_sqrt; - - for sqrt_n in (maximum_sqrt - 1_024.min((1_u128 << (<$T>::MAX.count_ones()/2)) - 1) as $T..maximum_sqrt).rev() { - isqrt_consistency_check(n); - assert_eq!( - n.isqrt(), - sqrt_n + 1, - "`{0}.pow(2).isqrt()` should be {0}.", - sqrt_n + 1 - ); - - n -= 1; - isqrt_consistency_check(n); - assert_eq!( - n.isqrt(), - sqrt_n, - "`({}.pow(2) - 1).isqrt()` should be {sqrt_n}.", - sqrt_n + 1 - ); - - n -= sqrt_n; - isqrt_consistency_check(n); - assert_eq!( - n.isqrt(), - sqrt_n, - "{n} is about halfway between `{sqrt_n}.pow(2)` and `{}.pow(2)`, so `{n}.isqrt()` should be {sqrt_n}.", - sqrt_n + 1 - ); - - n -= sqrt_n; - } - } - } - )* - }; -} - -macro_rules! signed_check { - ($T:ident) => { - /// This takes an input and, if it's nonnegative or - #[doc = concat!("`", stringify!($T), "::MIN`,")] - /// checks that `isqrt` and `checked_isqrt` produce equivalent results - /// for that input and for the negative of that input. - /// - /// # Note - /// - /// This cannot check that negative inputs to `isqrt` cause panics if - /// panics abort instead of unwind. - fn isqrt_consistency_check(n: $T) { - // `<$T>::MIN` will be negative, so ignore it in this nonnegative - // section. - if n >= 0 { - assert_eq!( - Some(n.isqrt()), - n.checked_isqrt(), - "`{n}.checked_isqrt()` should match `Some({n}.isqrt())`.", - ); - } - - // `wrapping_neg` so that `<$T>::MIN` will negate to itself rather - // than panicking. - let negative_n = n.wrapping_neg(); - - // Zero negated will still be nonnegative, so ignore it in this - // negative section. - if negative_n < 0 { - assert_eq!( - negative_n.checked_isqrt(), - None, - "`({negative_n}).checked_isqrt()` should be `None`, as {negative_n} is negative.", - ); - - // `catch_unwind` only works when panics unwind rather than abort. - #[cfg(panic = "unwind")] - { - std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| (-n).isqrt())).expect_err( - &format!("`({negative_n}).isqrt()` should have panicked, as {negative_n} is negative.") - ); - } - } - } - }; -} - -macro_rules! unsigned_check { - ($T:ident) => { - /// This takes an input and, if it's nonzero, checks that `isqrt` - /// produces the same numeric value for both - #[doc = concat!("`", stringify!($T), "` and ")] - #[doc = concat!("`NonZero<", stringify!($T), ">`.")] - fn isqrt_consistency_check(n: $T) { - // Zero cannot be turned into a `NonZero` value, so ignore it in - // this nonzero section. - if n > 0 { - assert_eq!( - n.isqrt(), - core::num::NonZero::<$T>::new(n) - .expect( - "Was not able to create a new `NonZero` value from a nonzero number." - ) - .isqrt() - .get(), - "`{n}.isqrt` should match `NonZero`'s `{n}.isqrt().get()`.", - ); - } - } - }; -} - -tests!(signed_check: i8 i16 i32 i64 i128); -tests!(unsigned_check: u8 u16 u32 u64 u128); diff --git a/library/core/tests/num/midpoint.rs b/library/core/tests/num/midpoint.rs deleted file mode 100644 index 71e98006784..00000000000 --- a/library/core/tests/num/midpoint.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Test the following expectations: -//! - midpoint(a, b) == (a + b) / 2 -//! - midpoint(a, b) == midpoint(b, a) -//! - midpoint(-a, -b) == -midpoint(a, b) - -#[test] -#[cfg(not(miri))] -fn midpoint_obvious_impl_i8() { - for a in i8::MIN..=i8::MAX { - for b in i8::MIN..=i8::MAX { - assert_eq!(i8::midpoint(a, b), ((a as i16 + b as i16) / 2) as i8); - } - } -} - -#[test] -#[cfg(not(miri))] -fn midpoint_obvious_impl_u8() { - for a in u8::MIN..=u8::MAX { - for b in u8::MIN..=u8::MAX { - assert_eq!(u8::midpoint(a, b), ((a as u16 + b as u16) / 2) as u8); - } - } -} - -#[test] -#[cfg(not(miri))] -fn midpoint_order_expectation_i8() { - for a in i8::MIN..=i8::MAX { - for b in i8::MIN..=i8::MAX { - assert_eq!(i8::midpoint(a, b), i8::midpoint(b, a)); - } - } -} - -#[test] -#[cfg(not(miri))] -fn midpoint_order_expectation_u8() { - for a in u8::MIN..=u8::MAX { - for b in u8::MIN..=u8::MAX { - assert_eq!(u8::midpoint(a, b), u8::midpoint(b, a)); - } - } -} - -#[test] -#[cfg(not(miri))] -fn midpoint_negative_expectation() { - for a in 0..=i8::MAX { - for b in 0..=i8::MAX { - assert_eq!(i8::midpoint(-a, -b), -i8::midpoint(a, b)); - } - } -} diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs deleted file mode 100644 index 0add9a01e68..00000000000 --- a/library/core/tests/num/mod.rs +++ /dev/null @@ -1,952 +0,0 @@ -use core::fmt::Debug; -use core::num::{IntErrorKind, ParseIntError, TryFromIntError, can_not_overflow}; -use core::ops::{Add, Div, Mul, Rem, Sub}; -use core::str::FromStr; - -#[macro_use] -mod int_macros; - -mod i128; -mod i16; -mod i32; -mod i64; -mod i8; - -#[macro_use] -mod uint_macros; - -mod u128; -mod u16; -mod u32; -mod u64; -mod u8; - -mod bignum; - -mod const_from; -mod dec2flt; -mod flt2dec; -mod int_log; -mod int_sqrt; -mod midpoint; -mod ops; -mod wrapping; - -mod float_iter_sum_identity; -mod ieee754; -mod nan; - -/// Adds the attribute to all items in the block. -macro_rules! cfg_block { - ($(#[$attr:meta]{$($it:item)*})*) => {$($( - #[$attr] - $it - )*)*} -} - -/// Groups items that assume the pointer width is either 16/32/64, and has to be altered if -/// support for larger/smaller pointer widths are added in the future. -macro_rules! assume_usize_width { - {$($it:item)*} => {#[cfg(not(any( - target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")))] - compile_error!("The current tests of try_from on usize/isize assume that \ - the pointer width is either 16, 32, or 64"); - $($it)* - } -} - -/// Helper function for testing numeric operations -pub fn test_num(ten: T, two: T) -where - T: PartialEq - + Add - + Sub - + Mul - + Div - + Rem - + Debug - + Copy, -{ - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); -} - -/// Helper function for asserting number parsing returns a specific error -fn test_parse(num_str: &str, expected: Result) -where - T: FromStr, - Result: PartialEq + Debug, -{ - assert_eq!(num_str.parse::().map_err(|e| e.kind().clone()), expected) -} - -#[test] -fn from_str_issue7588() { - let u: Option = u8::from_str_radix("1000", 10).ok(); - assert_eq!(u, None); - let s: Option = i16::from_str_radix("80000", 10).ok(); - assert_eq!(s, None); -} - -#[test] -fn test_int_from_str_overflow() { - test_parse::("127", Ok(127)); - test_parse::("128", Err(IntErrorKind::PosOverflow)); - - test_parse::("-128", Ok(-128)); - test_parse::("-129", Err(IntErrorKind::NegOverflow)); - - test_parse::("32767", Ok(32_767)); - test_parse::("32768", Err(IntErrorKind::PosOverflow)); - - test_parse::("-32768", Ok(-32_768)); - test_parse::("-32769", Err(IntErrorKind::NegOverflow)); - - test_parse::("2147483647", Ok(2_147_483_647)); - test_parse::("2147483648", Err(IntErrorKind::PosOverflow)); - - test_parse::("-2147483648", Ok(-2_147_483_648)); - test_parse::("-2147483649", Err(IntErrorKind::NegOverflow)); - - test_parse::("9223372036854775807", Ok(9_223_372_036_854_775_807)); - test_parse::("9223372036854775808", Err(IntErrorKind::PosOverflow)); - - test_parse::("-9223372036854775808", Ok(-9_223_372_036_854_775_808)); - test_parse::("-9223372036854775809", Err(IntErrorKind::NegOverflow)); -} - -#[test] -fn test_can_not_overflow() { - fn can_overflow(radix: u32, input: &str) -> bool - where - T: std::convert::TryFrom, - { - !can_not_overflow::(radix, T::try_from(-1_i8).is_ok(), input.as_bytes()) - } - - // Positive tests: - assert!(!can_overflow::(16, "F")); - assert!(!can_overflow::(16, "FF")); - - assert!(!can_overflow::(10, "9")); - assert!(!can_overflow::(10, "99")); - - // Negative tests: - - // Not currently in std lib (issue: #27728) - fn format_radix(mut x: T, radix: T) -> String - where - T: std::ops::Rem, - T: std::ops::Div, - T: std::cmp::PartialEq, - T: std::default::Default, - T: Copy, - T: Default, - u32: TryFrom, - { - let mut result = vec![]; - - loop { - let m = x % radix; - x = x / radix; - result.push( - std::char::from_digit(m.try_into().ok().unwrap(), radix.try_into().ok().unwrap()) - .unwrap(), - ); - if x == T::default() { - break; - } - } - result.into_iter().rev().collect() - } - - macro_rules! check { - ($($t:ty)*) => ($( - for base in 2..=36 { - let num = (<$t>::MAX as u128) + 1; - - // Calculate the string length for the smallest overflowing number: - let max_len_string = format_radix(num, base as u128); - // Ensure that string length is deemed to potentially overflow: - assert!(can_overflow::<$t>(base, &max_len_string)); - } - )*) - } - - check! { i8 i16 i32 i64 i128 isize usize u8 u16 u32 u64 } - - // Check u128 separately: - for base in 2..=36 { - let num = ::MAX; - let max_len_string = format_radix(num, base as u128); - // base 16 fits perfectly for u128 and won't overflow: - assert_eq!(can_overflow::(base, &max_len_string), base != 16); - } -} - -#[test] -fn test_leading_plus() { - test_parse::("+127", Ok(127)); - test_parse::("+9223372036854775807", Ok(9223372036854775807)); -} - -#[test] -fn test_invalid() { - test_parse::("--129", Err(IntErrorKind::InvalidDigit)); - test_parse::("++129", Err(IntErrorKind::InvalidDigit)); - test_parse::("Съешь", Err(IntErrorKind::InvalidDigit)); - test_parse::("123Hello", Err(IntErrorKind::InvalidDigit)); - test_parse::("--", Err(IntErrorKind::InvalidDigit)); - test_parse::("-", Err(IntErrorKind::InvalidDigit)); - test_parse::("+", Err(IntErrorKind::InvalidDigit)); - test_parse::("-1", Err(IntErrorKind::InvalidDigit)); -} - -#[test] -fn test_empty() { - test_parse::("", Err(IntErrorKind::Empty)); -} - -#[test] -fn test_infallible_try_from_int_error() { - let func = |x: i8| -> Result { Ok(x.try_into()?) }; - - assert!(func(0).is_ok()); -} - -const _TEST_CONST_PARSE: () = { - let Ok(-0x8000) = i16::from_str_radix("-8000", 16) else { panic!() }; - let Ok(12345) = u64::from_str_radix("12345", 10) else { panic!() }; - if let Err(e) = i8::from_str_radix("+", 10) { - let IntErrorKind::InvalidDigit = e.kind() else { panic!() }; - } else { - panic!() - } -}; - -macro_rules! test_impl_from { - ($fn_name:ident, bool, $target: ty) => { - #[test] - fn $fn_name() { - let one: $target = 1; - let zero: $target = 0; - assert_eq!(one, <$target>::from(true)); - assert_eq!(zero, <$target>::from(false)); - } - }; - ($fn_name: ident, $Small: ty, $Large: ty) => { - #[test] - fn $fn_name() { - let small_max = <$Small>::MAX; - let small_min = <$Small>::MIN; - let large_max: $Large = small_max.into(); - let large_min: $Large = small_min.into(); - assert_eq!(large_max as $Small, small_max); - assert_eq!(large_min as $Small, small_min); - } - }; -} - -// Unsigned -> Unsigned -test_impl_from! { test_u8u16, u8, u16 } -test_impl_from! { test_u8u32, u8, u32 } -test_impl_from! { test_u8u64, u8, u64 } -test_impl_from! { test_u8usize, u8, usize } -test_impl_from! { test_u16u32, u16, u32 } -test_impl_from! { test_u16u64, u16, u64 } -test_impl_from! { test_u32u64, u32, u64 } - -// Signed -> Signed -test_impl_from! { test_i8i16, i8, i16 } -test_impl_from! { test_i8i32, i8, i32 } -test_impl_from! { test_i8i64, i8, i64 } -test_impl_from! { test_i8isize, i8, isize } -test_impl_from! { test_i16i32, i16, i32 } -test_impl_from! { test_i16i64, i16, i64 } -test_impl_from! { test_i32i64, i32, i64 } - -// Unsigned -> Signed -test_impl_from! { test_u8i16, u8, i16 } -test_impl_from! { test_u8i32, u8, i32 } -test_impl_from! { test_u8i64, u8, i64 } -test_impl_from! { test_u16i32, u16, i32 } -test_impl_from! { test_u16i64, u16, i64 } -test_impl_from! { test_u32i64, u32, i64 } - -// Bool -> Integer -test_impl_from! { test_boolu8, bool, u8 } -test_impl_from! { test_boolu16, bool, u16 } -test_impl_from! { test_boolu32, bool, u32 } -test_impl_from! { test_boolu64, bool, u64 } -test_impl_from! { test_boolu128, bool, u128 } -test_impl_from! { test_booli8, bool, i8 } -test_impl_from! { test_booli16, bool, i16 } -test_impl_from! { test_booli32, bool, i32 } -test_impl_from! { test_booli64, bool, i64 } -test_impl_from! { test_booli128, bool, i128 } - -// Signed -> Float -test_impl_from! { test_i8f32, i8, f32 } -test_impl_from! { test_i8f64, i8, f64 } -test_impl_from! { test_i16f32, i16, f32 } -test_impl_from! { test_i16f64, i16, f64 } -test_impl_from! { test_i32f64, i32, f64 } - -// Unsigned -> Float -test_impl_from! { test_u8f32, u8, f32 } -test_impl_from! { test_u8f64, u8, f64 } -test_impl_from! { test_u16f32, u16, f32 } -test_impl_from! { test_u16f64, u16, f64 } -test_impl_from! { test_u32f64, u32, f64 } - -// Float -> Float -#[test] -fn test_f32f64() { - let max: f64 = f32::MAX.into(); - assert_eq!(max as f32, f32::MAX); - assert!(max.is_normal()); - - let min: f64 = f32::MIN.into(); - assert_eq!(min as f32, f32::MIN); - assert!(min.is_normal()); - - let min_positive: f64 = f32::MIN_POSITIVE.into(); - assert_eq!(min_positive as f32, f32::MIN_POSITIVE); - assert!(min_positive.is_normal()); - - let epsilon: f64 = f32::EPSILON.into(); - assert_eq!(epsilon as f32, f32::EPSILON); - assert!(epsilon.is_normal()); - - let zero: f64 = (0.0f32).into(); - assert_eq!(zero as f32, 0.0f32); - assert!(zero.is_sign_positive()); - - let neg_zero: f64 = (-0.0f32).into(); - assert_eq!(neg_zero as f32, -0.0f32); - assert!(neg_zero.is_sign_negative()); - - let infinity: f64 = f32::INFINITY.into(); - assert_eq!(infinity as f32, f32::INFINITY); - assert!(infinity.is_infinite()); - assert!(infinity.is_sign_positive()); - - let neg_infinity: f64 = f32::NEG_INFINITY.into(); - assert_eq!(neg_infinity as f32, f32::NEG_INFINITY); - assert!(neg_infinity.is_infinite()); - assert!(neg_infinity.is_sign_negative()); - - let nan: f64 = f32::NAN.into(); - assert!(nan.is_nan()); -} - -/// Conversions where the full width of $source can be represented as $target -macro_rules! test_impl_try_from_always_ok { - ($fn_name:ident, $source:ty, $target: ty) => { - #[test] - fn $fn_name() { - let max = <$source>::MAX; - let min = <$source>::MIN; - let zero: $source = 0; - assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); - } - }; -} - -test_impl_try_from_always_ok! { test_try_u8u8, u8, u8 } -test_impl_try_from_always_ok! { test_try_u8u16, u8, u16 } -test_impl_try_from_always_ok! { test_try_u8u32, u8, u32 } -test_impl_try_from_always_ok! { test_try_u8u64, u8, u64 } -test_impl_try_from_always_ok! { test_try_u8u128, u8, u128 } -test_impl_try_from_always_ok! { test_try_u8i16, u8, i16 } -test_impl_try_from_always_ok! { test_try_u8i32, u8, i32 } -test_impl_try_from_always_ok! { test_try_u8i64, u8, i64 } -test_impl_try_from_always_ok! { test_try_u8i128, u8, i128 } - -test_impl_try_from_always_ok! { test_try_u16u16, u16, u16 } -test_impl_try_from_always_ok! { test_try_u16u32, u16, u32 } -test_impl_try_from_always_ok! { test_try_u16u64, u16, u64 } -test_impl_try_from_always_ok! { test_try_u16u128, u16, u128 } -test_impl_try_from_always_ok! { test_try_u16i32, u16, i32 } -test_impl_try_from_always_ok! { test_try_u16i64, u16, i64 } -test_impl_try_from_always_ok! { test_try_u16i128, u16, i128 } - -test_impl_try_from_always_ok! { test_try_u32u32, u32, u32 } -test_impl_try_from_always_ok! { test_try_u32u64, u32, u64 } -test_impl_try_from_always_ok! { test_try_u32u128, u32, u128 } -test_impl_try_from_always_ok! { test_try_u32i64, u32, i64 } -test_impl_try_from_always_ok! { test_try_u32i128, u32, i128 } - -test_impl_try_from_always_ok! { test_try_u64u64, u64, u64 } -test_impl_try_from_always_ok! { test_try_u64u128, u64, u128 } -test_impl_try_from_always_ok! { test_try_u64i128, u64, i128 } - -test_impl_try_from_always_ok! { test_try_u128u128, u128, u128 } - -test_impl_try_from_always_ok! { test_try_i8i8, i8, i8 } -test_impl_try_from_always_ok! { test_try_i8i16, i8, i16 } -test_impl_try_from_always_ok! { test_try_i8i32, i8, i32 } -test_impl_try_from_always_ok! { test_try_i8i64, i8, i64 } -test_impl_try_from_always_ok! { test_try_i8i128, i8, i128 } - -test_impl_try_from_always_ok! { test_try_i16i16, i16, i16 } -test_impl_try_from_always_ok! { test_try_i16i32, i16, i32 } -test_impl_try_from_always_ok! { test_try_i16i64, i16, i64 } -test_impl_try_from_always_ok! { test_try_i16i128, i16, i128 } - -test_impl_try_from_always_ok! { test_try_i32i32, i32, i32 } -test_impl_try_from_always_ok! { test_try_i32i64, i32, i64 } -test_impl_try_from_always_ok! { test_try_i32i128, i32, i128 } - -test_impl_try_from_always_ok! { test_try_i64i64, i64, i64 } -test_impl_try_from_always_ok! { test_try_i64i128, i64, i128 } - -test_impl_try_from_always_ok! { test_try_i128i128, i128, i128 } - -test_impl_try_from_always_ok! { test_try_usizeusize, usize, usize } -test_impl_try_from_always_ok! { test_try_isizeisize, isize, isize } - -assume_usize_width! { - test_impl_try_from_always_ok! { test_try_u8usize, u8, usize } - test_impl_try_from_always_ok! { test_try_u8isize, u8, isize } - test_impl_try_from_always_ok! { test_try_i8isize, i8, isize } - - test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } - test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } - - test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } - test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } - test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } - - test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } - test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } - test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } - test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } - test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } - test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } - test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } - test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } - test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } - test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } - test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } - test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } - test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } - test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } - test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } - test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } - test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } - } - ); -} - -/// Conversions where max of $source can be represented as $target, -macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok { - ($fn_name:ident, $source:ty, $target:ty) => { - #[test] - fn $fn_name() { - let max = <$source>::MAX; - let min = <$source>::MIN; - let zero: $source = 0; - let neg_one: $source = -1; - assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target); - assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); - assert!(<$target as TryFrom<$source>>::try_from(neg_one).is_err()); - } - }; -} - -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u8, i8, u8 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u16, i8, u16 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u32, i8, u32 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u64, i8, u64 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u128, i8, u128 } - -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u16, i16, u16 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u32, i16, u32 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u64, i16, u64 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u128, i16, u128 } - -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u32, i32, u32 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u64, i32, u64 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u128, i32, u128 } - -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u64, i64, u64 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u128, i64, u128 } - -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i128u128, i128, u128 } - -assume_usize_width! { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8usize, i8, usize } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16usize, i16, usize } - - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } - - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } - } - ); -} - -/// Conversions where max of $source can not be represented as $target, -/// but min can. -macro_rules! test_impl_try_from_unsigned_to_signed_upper_err { - ($fn_name:ident, $source:ty, $target:ty) => { - #[test] - fn $fn_name() { - let max = <$source>::MAX; - let min = <$source>::MIN; - let zero: $source = 0; - assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); - assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); - } - }; -} - -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u8i8, u8, i8 } - -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i8, u16, i8 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i16, u16, i16 } - -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i8, u32, i8 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i16, u32, i16 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i32, u32, i32 } - -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i8, u64, i8 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i16, u64, i16 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i32, u64, i32 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i64, u64, i64 } - -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i8, u128, i8 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i16, u128, i16 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i32, u128, i32 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } - -assume_usize_width! { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } - - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } - } - ); -} - -/// Conversions where min/max of $source can not be represented as $target. -macro_rules! test_impl_try_from_same_sign_err { - ($fn_name:ident, $source:ty, $target:ty) => { - #[test] - fn $fn_name() { - let max = <$source>::MAX; - let min = <$source>::MIN; - let zero: $source = 0; - let t_max = <$target>::MAX; - let t_min = <$target>::MIN; - assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); - if min != 0 { - assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); - } - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); - assert_eq!( - <$target as TryFrom<$source>>::try_from(t_max as $source).unwrap(), - t_max as $target - ); - assert_eq!( - <$target as TryFrom<$source>>::try_from(t_min as $source).unwrap(), - t_min as $target - ); - } - }; -} - -test_impl_try_from_same_sign_err! { test_try_u16u8, u16, u8 } - -test_impl_try_from_same_sign_err! { test_try_u32u8, u32, u8 } -test_impl_try_from_same_sign_err! { test_try_u32u16, u32, u16 } - -test_impl_try_from_same_sign_err! { test_try_u64u8, u64, u8 } -test_impl_try_from_same_sign_err! { test_try_u64u16, u64, u16 } -test_impl_try_from_same_sign_err! { test_try_u64u32, u64, u32 } - -test_impl_try_from_same_sign_err! { test_try_u128u8, u128, u8 } -test_impl_try_from_same_sign_err! { test_try_u128u16, u128, u16 } -test_impl_try_from_same_sign_err! { test_try_u128u32, u128, u32 } -test_impl_try_from_same_sign_err! { test_try_u128u64, u128, u64 } - -test_impl_try_from_same_sign_err! { test_try_i16i8, i16, i8 } -test_impl_try_from_same_sign_err! { test_try_isizei8, isize, i8 } - -test_impl_try_from_same_sign_err! { test_try_i32i8, i32, i8 } -test_impl_try_from_same_sign_err! { test_try_i32i16, i32, i16 } - -test_impl_try_from_same_sign_err! { test_try_i64i8, i64, i8 } -test_impl_try_from_same_sign_err! { test_try_i64i16, i64, i16 } -test_impl_try_from_same_sign_err! { test_try_i64i32, i64, i32 } - -test_impl_try_from_same_sign_err! { test_try_i128i8, i128, i8 } -test_impl_try_from_same_sign_err! { test_try_i128i16, i128, i16 } -test_impl_try_from_same_sign_err! { test_try_i128i32, i128, i32 } -test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } - -assume_usize_width! { - test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } - test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } - test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } - test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } - - test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } - test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } - test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } - - test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } - test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } - test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } - - test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } - test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } - } - ); -} - -/// Conversions where neither the min nor the max of $source can be represented by -/// $target, but max/min of the target can be represented by the source. -macro_rules! test_impl_try_from_signed_to_unsigned_err { - ($fn_name:ident, $source:ty, $target:ty) => { - #[test] - fn $fn_name() { - let max = <$source>::MAX; - let min = <$source>::MIN; - let zero: $source = 0; - let t_max = <$target>::MAX; - let t_min = <$target>::MIN; - assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); - assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); - assert_eq!( - <$target as TryFrom<$source>>::try_from(t_max as $source).unwrap(), - t_max as $target - ); - assert_eq!( - <$target as TryFrom<$source>>::try_from(t_min as $source).unwrap(), - t_min as $target - ); - } - }; -} - -test_impl_try_from_signed_to_unsigned_err! { test_try_i16u8, i16, u8 } - -test_impl_try_from_signed_to_unsigned_err! { test_try_i32u8, i32, u8 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i32u16, i32, u16 } - -test_impl_try_from_signed_to_unsigned_err! { test_try_i64u8, i64, u8 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i64u16, i64, u16 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i64u32, i64, u32 } - -test_impl_try_from_signed_to_unsigned_err! { test_try_i128u8, i128, u8 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i128u16, i128, u16 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i128u32, i128, u32 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } - -assume_usize_width! { - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } - test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } - - cfg_block! { - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } - test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } - } - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } - - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } - } - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } - } - } -} - -macro_rules! test_float { - ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => { - mod $modname { - #[test] - fn min() { - assert_eq!((0.0 as $fty).min(0.0), 0.0); - assert!((0.0 as $fty).min(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).min(-0.0), -0.0); - assert!((-0.0 as $fty).min(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).min(9.0), 9.0); - assert_eq!((-9.0 as $fty).min(0.0), -9.0); - assert_eq!((0.0 as $fty).min(9.0), 0.0); - assert!((0.0 as $fty).min(9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).min(9.0), -0.0); - assert!((-0.0 as $fty).min(9.0).is_sign_negative()); - assert_eq!((-0.0 as $fty).min(-9.0), -9.0); - assert_eq!(($inf as $fty).min(9.0), 9.0); - assert_eq!((9.0 as $fty).min($inf), 9.0); - assert_eq!(($inf as $fty).min(-9.0), -9.0); - assert_eq!((-9.0 as $fty).min($inf), -9.0); - assert_eq!(($neginf as $fty).min(9.0), $neginf); - assert_eq!((9.0 as $fty).min($neginf), $neginf); - assert_eq!(($neginf as $fty).min(-9.0), $neginf); - assert_eq!((-9.0 as $fty).min($neginf), $neginf); - assert_eq!(($nan as $fty).min(9.0), 9.0); - assert_eq!(($nan as $fty).min(-9.0), -9.0); - assert_eq!((9.0 as $fty).min($nan), 9.0); - assert_eq!((-9.0 as $fty).min($nan), -9.0); - assert!(($nan as $fty).min($nan).is_nan()); - } - #[test] - fn max() { - assert_eq!((0.0 as $fty).max(0.0), 0.0); - assert!((0.0 as $fty).max(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).max(-0.0), -0.0); - assert!((-0.0 as $fty).max(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).max(9.0), 9.0); - assert_eq!((-9.0 as $fty).max(0.0), 0.0); - assert!((-9.0 as $fty).max(0.0).is_sign_positive()); - assert_eq!((-9.0 as $fty).max(-0.0), -0.0); - assert!((-9.0 as $fty).max(-0.0).is_sign_negative()); - assert_eq!((0.0 as $fty).max(9.0), 9.0); - assert_eq!((0.0 as $fty).max(-9.0), 0.0); - assert!((0.0 as $fty).max(-9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).max(-9.0), -0.0); - assert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - assert_eq!(($inf as $fty).max(9.0), $inf); - assert_eq!((9.0 as $fty).max($inf), $inf); - assert_eq!(($inf as $fty).max(-9.0), $inf); - assert_eq!((-9.0 as $fty).max($inf), $inf); - assert_eq!(($neginf as $fty).max(9.0), 9.0); - assert_eq!((9.0 as $fty).max($neginf), 9.0); - assert_eq!(($neginf as $fty).max(-9.0), -9.0); - assert_eq!((-9.0 as $fty).max($neginf), -9.0); - assert_eq!(($nan as $fty).max(9.0), 9.0); - assert_eq!(($nan as $fty).max(-9.0), -9.0); - assert_eq!((9.0 as $fty).max($nan), 9.0); - assert_eq!((-9.0 as $fty).max($nan), -9.0); - assert!(($nan as $fty).max($nan).is_nan()); - } - #[test] - fn minimum() { - assert_eq!((0.0 as $fty).minimum(0.0), 0.0); - assert!((0.0 as $fty).minimum(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).minimum(0.0), -0.0); - assert!((-0.0 as $fty).minimum(0.0).is_sign_negative()); - assert_eq!((-0.0 as $fty).minimum(-0.0), -0.0); - assert!((-0.0 as $fty).minimum(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).minimum(9.0), 9.0); - assert_eq!((-9.0 as $fty).minimum(0.0), -9.0); - assert_eq!((0.0 as $fty).minimum(9.0), 0.0); - assert!((0.0 as $fty).minimum(9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).minimum(9.0), -0.0); - assert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); - assert_eq!((-0.0 as $fty).minimum(-9.0), -9.0); - assert_eq!(($inf as $fty).minimum(9.0), 9.0); - assert_eq!((9.0 as $fty).minimum($inf), 9.0); - assert_eq!(($inf as $fty).minimum(-9.0), -9.0); - assert_eq!((-9.0 as $fty).minimum($inf), -9.0); - assert_eq!(($neginf as $fty).minimum(9.0), $neginf); - assert_eq!((9.0 as $fty).minimum($neginf), $neginf); - assert_eq!(($neginf as $fty).minimum(-9.0), $neginf); - assert_eq!((-9.0 as $fty).minimum($neginf), $neginf); - assert!(($nan as $fty).minimum(9.0).is_nan()); - assert!(($nan as $fty).minimum(-9.0).is_nan()); - assert!((9.0 as $fty).minimum($nan).is_nan()); - assert!((-9.0 as $fty).minimum($nan).is_nan()); - assert!(($nan as $fty).minimum($nan).is_nan()); - } - #[test] - fn maximum() { - assert_eq!((0.0 as $fty).maximum(0.0), 0.0); - assert!((0.0 as $fty).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).maximum(0.0), 0.0); - assert!((-0.0 as $fty).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).maximum(-0.0), -0.0); - assert!((-0.0 as $fty).maximum(-0.0).is_sign_negative()); - assert_eq!((9.0 as $fty).maximum(9.0), 9.0); - assert_eq!((-9.0 as $fty).maximum(0.0), 0.0); - assert!((-9.0 as $fty).maximum(0.0).is_sign_positive()); - assert_eq!((-9.0 as $fty).maximum(-0.0), -0.0); - assert!((-9.0 as $fty).maximum(-0.0).is_sign_negative()); - assert_eq!((0.0 as $fty).maximum(9.0), 9.0); - assert_eq!((0.0 as $fty).maximum(-9.0), 0.0); - assert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); - assert_eq!((-0.0 as $fty).maximum(-9.0), -0.0); - assert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - assert_eq!(($inf as $fty).maximum(9.0), $inf); - assert_eq!((9.0 as $fty).maximum($inf), $inf); - assert_eq!(($inf as $fty).maximum(-9.0), $inf); - assert_eq!((-9.0 as $fty).maximum($inf), $inf); - assert_eq!(($neginf as $fty).maximum(9.0), 9.0); - assert_eq!((9.0 as $fty).maximum($neginf), 9.0); - assert_eq!(($neginf as $fty).maximum(-9.0), -9.0); - assert_eq!((-9.0 as $fty).maximum($neginf), -9.0); - assert!(($nan as $fty).maximum(9.0).is_nan()); - assert!(($nan as $fty).maximum(-9.0).is_nan()); - assert!((9.0 as $fty).maximum($nan).is_nan()); - assert!((-9.0 as $fty).maximum($nan).is_nan()); - assert!(($nan as $fty).maximum($nan).is_nan()); - } - #[test] - fn midpoint() { - assert_eq!((0.5 as $fty).midpoint(0.5), 0.5); - assert_eq!((0.5 as $fty).midpoint(2.5), 1.5); - assert_eq!((3.0 as $fty).midpoint(4.0), 3.5); - assert_eq!((-3.0 as $fty).midpoint(4.0), 0.5); - assert_eq!((3.0 as $fty).midpoint(-4.0), -0.5); - assert_eq!((-3.0 as $fty).midpoint(-4.0), -3.5); - assert_eq!((0.0 as $fty).midpoint(0.0), 0.0); - assert_eq!((-0.0 as $fty).midpoint(-0.0), -0.0); - assert_eq!((-5.0 as $fty).midpoint(5.0), 0.0); - assert_eq!(($max as $fty).midpoint($min), 0.0); - assert_eq!(($min as $fty).midpoint($max), -0.0); - assert_eq!(($max as $fty).midpoint($min_pos), $max / 2.); - assert_eq!((-$max as $fty).midpoint($min_pos), -$max / 2.); - assert_eq!(($max as $fty).midpoint(-$min_pos), $max / 2.); - assert_eq!((-$max as $fty).midpoint(-$min_pos), -$max / 2.); - assert_eq!(($min_pos as $fty).midpoint($max), $max / 2.); - assert_eq!(($min_pos as $fty).midpoint(-$max), -$max / 2.); - assert_eq!((-$min_pos as $fty).midpoint($max), $max / 2.); - assert_eq!((-$min_pos as $fty).midpoint(-$max), -$max / 2.); - assert_eq!(($max as $fty).midpoint($max), $max); - assert_eq!(($min_pos as $fty).midpoint($min_pos), $min_pos); - assert_eq!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos); - assert_eq!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5); - assert_eq!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5); - assert_eq!(($inf as $fty).midpoint($inf), $inf); - assert_eq!(($neginf as $fty).midpoint($neginf), $neginf); - assert!(($nan as $fty).midpoint(1.0).is_nan()); - assert!((1.0 as $fty).midpoint($nan).is_nan()); - assert!(($nan as $fty).midpoint($nan).is_nan()); - - // test if large differences in magnitude are still correctly computed. - // NOTE: that because of how small x and y are, x + y can never overflow - // so (x + y) / 2.0 is always correct - // in particular, `2.pow(i)` will never be at the max exponent, so it could - // be safely doubled, while j is significantly smaller. - for i in $max_exp.saturating_sub(64)..$max_exp { - for j in 0..64u8 { - let large = <$fty>::from(2.0f32).powi(i); - // a much smaller number, such that there is no chance of overflow to test - // potential double rounding in midpoint's implementation. - let small = <$fty>::from(2.0f32).powi($max_exp - 1) - * <$fty>::EPSILON - * <$fty>::from(j); - - let naive = (large + small) / 2.0; - let midpoint = large.midpoint(small); - - assert_eq!(naive, midpoint); - } - } - } - #[test] - fn rem_euclid() { - let a: $fty = 42.0; - assert!($inf.rem_euclid(a).is_nan()); - assert_eq!(a.rem_euclid($inf), a); - assert!(a.rem_euclid($nan).is_nan()); - assert!($inf.rem_euclid($inf).is_nan()); - assert!($inf.rem_euclid($nan).is_nan()); - assert!($nan.rem_euclid($inf).is_nan()); - } - #[test] - fn div_euclid() { - let a: $fty = 42.0; - assert_eq!(a.div_euclid($inf), 0.0); - assert!(a.div_euclid($nan).is_nan()); - assert!($inf.div_euclid($inf).is_nan()); - assert!($inf.div_euclid($nan).is_nan()); - assert!($nan.div_euclid($inf).is_nan()); - } - } - }; -} - -test_float!( - f32, - f32, - f32::INFINITY, - f32::NEG_INFINITY, - f32::NAN, - f32::MIN, - f32::MAX, - f32::MIN_POSITIVE, - f32::MAX_EXP -); -test_float!( - f64, - f64, - f64::INFINITY, - f64::NEG_INFINITY, - f64::NAN, - f64::MIN, - f64::MAX, - f64::MIN_POSITIVE, - f64::MAX_EXP -); diff --git a/library/core/tests/num/nan.rs b/library/core/tests/num/nan.rs deleted file mode 100644 index ef81988c961..00000000000 --- a/library/core/tests/num/nan.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[test] -fn test_nan() { - let x = "NaN".to_string(); - assert_eq!(format!("{}", f64::NAN), x); - assert_eq!(format!("{:e}", f64::NAN), x); - assert_eq!(format!("{:E}", f64::NAN), x); -} diff --git a/library/core/tests/num/ops.rs b/library/core/tests/num/ops.rs deleted file mode 100644 index 7b2aad48978..00000000000 --- a/library/core/tests/num/ops.rs +++ /dev/null @@ -1,238 +0,0 @@ -use core::ops::*; - -// For types L and R, checks that a trait implementation exists for -// * binary ops: L op R, L op &R, &L op R and &L op &R -// * assign ops: &mut L op R, &mut L op &R -macro_rules! impl_defined { - ($op:ident, $method:ident($lhs:literal, $rhs:literal), $result:literal, $lt:ty, $rt:ty) => { - let lhs = $lhs as $lt; - let rhs = $rhs as $rt; - assert_eq!($result as $lt, $op::$method(lhs, rhs)); - assert_eq!($result as $lt, $op::$method(lhs, &rhs)); - assert_eq!($result as $lt, $op::$method(&lhs, rhs)); - assert_eq!($result as $lt, $op::$method(&lhs, &rhs)); - }; - ($op:ident, $method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $lt:ty, $rt:ty) => { - let rhs = $rhs as $rt; - let mut lhs = $lhs as $lt; - $op::$method(&mut lhs, rhs); - assert_eq!($result as $lt, lhs); - - let mut lhs = $lhs as $lt; - $op::$method(&mut lhs, &rhs); - assert_eq!($result as $lt, lhs); - }; -} - -// For all specified types T, checks that a trait implementation exists for -// * binary ops: T op T, T op &T, &T op T and &T op &T -// * assign ops: &mut T op T, &mut T op &T -// * unary ops: op T and op &T -macro_rules! impls_defined { - ($op:ident, $method:ident($lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {$( - impl_defined!($op, $method($lhs, $rhs), $result, $t, $t); - )+}; - ($op:ident, $method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {$( - impl_defined!($op, $method(&mut $lhs, $rhs), $result, $t, $t); - )+}; - ($op:ident, $method:ident($operand:literal), $result:literal, $($t:ty),+) => {$( - let operand = $operand as $t; - assert_eq!($result as $t, $op::$method(operand)); - assert_eq!($result as $t, $op::$method(&operand)); - )+}; -} - -macro_rules! test_op { - ($fn_name:ident, $op:ident::$method:ident($lhs:literal), $result:literal, $($t:ty),+) => { - #[test] - fn $fn_name() { - impls_defined!($op, $method($lhs), $result, $($t),+); - } - }; -} - -test_op!(test_neg_defined, Neg::neg(0), 0, i8, i16, i32, i64, i128, f32, f64); - -test_op!(test_not_defined_bool, Not::not(true), false, bool); - -macro_rules! test_arith_op { - ($fn_name:ident, $op:ident::$method:ident($lhs:literal, $rhs:literal)) => { - #[test] - fn $fn_name() { - impls_defined!( - $op, - $method($lhs, $rhs), - 0, - i8, - i16, - i32, - i64, - i128, - isize, - u8, - u16, - u32, - u64, - u128, - usize, - f32, - f64 - ); - } - }; - ($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal)) => { - #[test] - fn $fn_name() { - impls_defined!( - $op, - $method(&mut $lhs, $rhs), - 0, - i8, - i16, - i32, - i64, - i128, - isize, - u8, - u16, - u32, - u64, - u128, - usize, - f32, - f64 - ); - } - }; -} - -test_arith_op!(test_add_defined, Add::add(0, 0)); -test_arith_op!(test_add_assign_defined, AddAssign::add_assign(&mut 0, 0)); -test_arith_op!(test_sub_defined, Sub::sub(0, 0)); -test_arith_op!(test_sub_assign_defined, SubAssign::sub_assign(&mut 0, 0)); -test_arith_op!(test_mul_defined, Mul::mul(0, 0)); -test_arith_op!(test_mul_assign_defined, MulAssign::mul_assign(&mut 0, 0)); -test_arith_op!(test_div_defined, Div::div(0, 1)); -test_arith_op!(test_div_assign_defined, DivAssign::div_assign(&mut 0, 1)); -test_arith_op!(test_rem_defined, Rem::rem(0, 1)); -test_arith_op!(test_rem_assign_defined, RemAssign::rem_assign(&mut 0, 1)); - -macro_rules! test_bitop { - ($test_name:ident, $op:ident::$method:ident) => { - #[test] - fn $test_name() { - impls_defined!( - $op, - $method(0, 0), - 0, - i8, - i16, - i32, - i64, - i128, - isize, - u8, - u16, - u32, - u64, - u128, - usize - ); - impls_defined!($op, $method(false, false), false, bool); - } - }; -} -macro_rules! test_bitop_assign { - ($test_name:ident, $op:ident::$method:ident) => { - #[test] - fn $test_name() { - impls_defined!( - $op, - $method(&mut 0, 0), - 0, - i8, - i16, - i32, - i64, - i128, - isize, - u8, - u16, - u32, - u64, - u128, - usize - ); - impls_defined!($op, $method(&mut false, false), false, bool); - } - }; -} - -test_bitop!(test_bitand_defined, BitAnd::bitand); -test_bitop_assign!(test_bitand_assign_defined, BitAndAssign::bitand_assign); -test_bitop!(test_bitor_defined, BitOr::bitor); -test_bitop_assign!(test_bitor_assign_defined, BitOrAssign::bitor_assign); -test_bitop!(test_bitxor_defined, BitXor::bitxor); -test_bitop_assign!(test_bitxor_assign_defined, BitXorAssign::bitxor_assign); - -macro_rules! test_shift_inner { - ($op:ident::$method:ident, $lt:ty, $($rt:ty),+) => { - $(impl_defined!($op, $method(0,0), 0, $lt, $rt);)+ - }; - ($op:ident::$method:ident, $lt:ty) => { - test_shift_inner!( - $op::$method, $lt, - i8, i16, i32, i64, i128, isize, - u8, u16, u32, u64, u128, usize - ); - }; -} - -macro_rules! test_shift { - ($op:ident::$method:ident, $($lt:ty),+) => { - $(test_shift_inner!($op::$method, $lt);)+ - }; - ($test_name:ident, $op:ident::$method:ident) => { - #[test] - fn $test_name() { - test_shift!( - $op::$method, - i8, i16, i32, i64, i128, isize, - u8, u16, u32, u64, u128, usize - ); - } - }; -} - -macro_rules! test_shift_assign_inner { - ($op:ident::$method:ident, $lt:ty, $($rt:ty),+) => { - $(impl_defined!($op, $method(&mut 0,0), 0, $lt, $rt);)+ - }; - ($op:ident::$method:ident, $lt:ty) => { - test_shift_assign_inner!( - $op::$method, $lt, - i8, i16, i32, i64, i128, isize, - u8, u16, u32, u64, u128, usize - ); - }; -} - -macro_rules! test_shift_assign { - ($op:ident::$method:ident, $($lt:ty),+) => { - $(test_shift_assign_inner!($op::$method, $lt);)+ - }; - ($test_name:ident, $op:ident::$method:ident) => { - #[test] - fn $test_name() { - test_shift_assign!( - $op::$method, - i8, i16, i32, i64, i128, isize, - u8, u16, u32, u64, u128, usize - ); - } - }; -} -test_shift!(test_shl_defined, Shl::shl); -test_shift_assign!(test_shl_assign_defined, ShlAssign::shl_assign); -test_shift!(test_shr_defined, Shr::shr); -test_shift_assign!(test_shr_assign_defined, ShrAssign::shr_assign); diff --git a/library/core/tests/num/u128.rs b/library/core/tests/num/u128.rs deleted file mode 100644 index a7b0f9effef..00000000000 --- a/library/core/tests/num/u128.rs +++ /dev/null @@ -1 +0,0 @@ -uint_module!(u128); diff --git a/library/core/tests/num/u16.rs b/library/core/tests/num/u16.rs deleted file mode 100644 index 010596a34a5..00000000000 --- a/library/core/tests/num/u16.rs +++ /dev/null @@ -1 +0,0 @@ -uint_module!(u16); diff --git a/library/core/tests/num/u32.rs b/library/core/tests/num/u32.rs deleted file mode 100644 index 687d3bbaa90..00000000000 --- a/library/core/tests/num/u32.rs +++ /dev/null @@ -1 +0,0 @@ -uint_module!(u32); diff --git a/library/core/tests/num/u64.rs b/library/core/tests/num/u64.rs deleted file mode 100644 index ee55071e949..00000000000 --- a/library/core/tests/num/u64.rs +++ /dev/null @@ -1 +0,0 @@ -uint_module!(u64); diff --git a/library/core/tests/num/u8.rs b/library/core/tests/num/u8.rs deleted file mode 100644 index 12b038ce0f7..00000000000 --- a/library/core/tests/num/u8.rs +++ /dev/null @@ -1 +0,0 @@ -uint_module!(u8); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs deleted file mode 100644 index 99a2d4cd462..00000000000 --- a/library/core/tests/num/uint_macros.rs +++ /dev/null @@ -1,321 +0,0 @@ -macro_rules! uint_module { - ($T:ident) => { - use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; - use core::$T::*; - - use crate::num; - - #[test] - fn test_overflows() { - assert!(MAX > 0); - assert!(MIN <= 0); - assert!((MIN + MAX).wrapping_add(1) == 0); - } - - #[test] - fn test_num() { - num::test_num(10 as $T, 2 as $T); - } - - #[test] - fn test_bitwise_operators() { - assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T)); - assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T)); - assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T)); - assert!(0b1110 as $T == (0b0111 as $T).shl(1)); - assert!(0b0111 as $T == (0b1110 as $T).shr(1)); - assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not()); - } - - const A: $T = 0b0101100; - const B: $T = 0b0100001; - const C: $T = 0b1111001; - - const _0: $T = 0; - const _1: $T = !0; - - test_runtime_and_compiletime! { - fn test_count_ones() { - assert!(A.count_ones() == 3); - assert!(B.count_ones() == 2); - assert!(C.count_ones() == 5); - } - - fn test_count_zeros() { - assert!(A.count_zeros() == $T::BITS - 3); - assert!(B.count_zeros() == $T::BITS - 2); - assert!(C.count_zeros() == $T::BITS - 5); - } - - fn test_leading_trailing_ones() { - const A: $T = 0b0101_1111; - assert_eq_const_safe!(A.trailing_ones(), 5); - assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); - - assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); - - assert_eq_const_safe!(_1.leading_ones(), $T::BITS); - assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); - - assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); - assert_eq_const_safe!((_1 >> 1).leading_ones(), 0); - - assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); - assert_eq_const_safe!((_1 >> 1).trailing_ones(), $T::BITS - 1); - - assert_eq_const_safe!(_0.leading_ones(), 0); - assert_eq_const_safe!(_0.trailing_ones(), 0); - - const X: $T = 0b0010_1100; - assert_eq_const_safe!(X.leading_ones(), 0); - assert_eq_const_safe!(X.trailing_ones(), 0); - } - - fn test_rotate() { - assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); - assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); - assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); - - // Rotating these should make no difference - // - // We test using 124 bits because to ensure that overlong bit shifts do - // not cause undefined behavior. See #10183. - assert_eq_const_safe!(_0.rotate_left(124), _0); - assert_eq_const_safe!(_1.rotate_left(124), _1); - assert_eq_const_safe!(_0.rotate_right(124), _0); - assert_eq_const_safe!(_1.rotate_right(124), _1); - - // Rotating by 0 should have no effect - assert_eq_const_safe!(A.rotate_left(0), A); - assert_eq_const_safe!(B.rotate_left(0), B); - assert_eq_const_safe!(C.rotate_left(0), C); - // Rotating by a multiple of word size should also have no effect - assert_eq_const_safe!(A.rotate_left(128), A); - assert_eq_const_safe!(B.rotate_left(128), B); - assert_eq_const_safe!(C.rotate_left(128), C); - } - - fn test_swap_bytes() { - assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); - assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); - assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); - - // Swapping these should make no difference - assert_eq_const_safe!(_0.swap_bytes(), _0); - assert_eq_const_safe!(_1.swap_bytes(), _1); - } - - fn test_reverse_bits() { - assert_eq_const_safe!(A.reverse_bits().reverse_bits(), A); - assert_eq_const_safe!(B.reverse_bits().reverse_bits(), B); - assert_eq_const_safe!(C.reverse_bits().reverse_bits(), C); - - // Swapping these should make no difference - assert_eq_const_safe!(_0.reverse_bits(), _0); - assert_eq_const_safe!(_1.reverse_bits(), _1); - } - - fn test_le() { - assert_eq_const_safe!($T::from_le(A.to_le()), A); - assert_eq_const_safe!($T::from_le(B.to_le()), B); - assert_eq_const_safe!($T::from_le(C.to_le()), C); - assert_eq_const_safe!($T::from_le(_0), _0); - assert_eq_const_safe!($T::from_le(_1), _1); - assert_eq_const_safe!(_0.to_le(), _0); - assert_eq_const_safe!(_1.to_le(), _1); - } - - fn test_be() { - assert_eq_const_safe!($T::from_be(A.to_be()), A); - assert_eq_const_safe!($T::from_be(B.to_be()), B); - assert_eq_const_safe!($T::from_be(C.to_be()), C); - assert_eq_const_safe!($T::from_be(_0), _0); - assert_eq_const_safe!($T::from_be(_1), _1); - assert_eq_const_safe!(_0.to_be(), _0); - assert_eq_const_safe!(_1.to_be(), _1); - } - - fn test_unsigned_checked_div() { - assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); - assert_eq_const_safe!((5 as $T).checked_div(0), None); - } - } - - fn from_str(t: &str) -> Option { - core::str::FromStr::from_str(t).ok() - } - - #[test] - pub fn test_from_str() { - assert_eq!(from_str::<$T>("0"), Some(0 as $T)); - assert_eq!(from_str::<$T>("3"), Some(3 as $T)); - assert_eq!(from_str::<$T>("10"), Some(10 as $T)); - assert_eq!(from_str::("123456789"), Some(123456789 as u32)); - assert_eq!(from_str::<$T>("00100"), Some(100 as $T)); - - assert_eq!(from_str::<$T>(""), None); - assert_eq!(from_str::<$T>(" "), None); - assert_eq!(from_str::<$T>("x"), None); - } - - test_runtime_and_compiletime! { - fn test_parse_bytes() { - assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq_const_safe!(u16::from_str_radix("123", 16), Ok(291 as u16)); - assert_eq_const_safe!(u16::from_str_radix("ffff", 16), Ok(65535 as u16)); - assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); - - assert!($T::from_str_radix("Z", 10).is_err()); - assert!($T::from_str_radix("_", 2).is_err()); - } - - fn test_pow() { - { - const R: $T = 2; - assert_eq_const_safe!(R.pow(2), 4 as $T); - assert_eq_const_safe!(R.pow(0), 1 as $T); - assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); - assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); - assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); - assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); - assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); - assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); - assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); - } - - { - const R: $T = $T::MAX; - // use `^` to represent .pow() with no overflow. - // if itest::MAX == 2^j-1, then itest is a `j` bit int, - // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, - // thussaturating_pow the overflowing result is exactly 1. - assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); - assert_eq_const_safe!(R.checked_pow(2), None); - assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); - assert_eq_const_safe!(R.saturating_pow(2), MAX); - } - } - - fn test_isqrt() { - assert_eq_const_safe!((0 as $T).isqrt(), 0 as $T); - assert_eq_const_safe!((1 as $T).isqrt(), 1 as $T); - assert_eq_const_safe!((2 as $T).isqrt(), 1 as $T); - assert_eq_const_safe!((99 as $T).isqrt(), 9 as $T); - assert_eq_const_safe!((100 as $T).isqrt(), 10 as $T); - assert_eq_const_safe!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1); - } - } - - #[cfg(not(miri))] // Miri is too slow - #[test] - fn test_lots_of_isqrt() { - let n_max: $T = (1024 * 1024).min($T::MAX as u128) as $T; - for n in 0..=n_max { - let isqrt: $T = n.isqrt(); - - assert!(isqrt.pow(2) <= n); - assert!(isqrt + 1 == (1 as $T) << ($T::BITS / 2) || (isqrt + 1).pow(2) > n); - } - - for n in ($T::MAX - 255)..=$T::MAX { - let isqrt: $T = n.isqrt(); - - assert!(isqrt.pow(2) <= n); - assert!(isqrt + 1 == (1 as $T) << ($T::BITS / 2) || (isqrt + 1).pow(2) > n); - } - } - - test_runtime_and_compiletime! { - fn test_div_floor() { - assert_eq_const_safe!((8 as $T).div_floor(3), 2); - } - - fn test_div_ceil() { - assert_eq_const_safe!((8 as $T).div_ceil(3), 3); - } - - fn test_next_multiple_of() { - assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); - assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); - assert_eq_const_safe!(MAX.next_multiple_of(1), MAX); - } - - fn test_checked_next_multiple_of() { - assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); - assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); - assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); - assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); - } - - fn test_is_next_multiple_of() { - assert!((12 as $T).is_multiple_of(4)); - assert!(!(12 as $T).is_multiple_of(5)); - assert!((0 as $T).is_multiple_of(0)); - assert!(!(12 as $T).is_multiple_of(0)); - } - - fn test_carrying_add() { - assert_eq_const_safe!($T::MAX.carrying_add(1, false), (0, true)); - assert_eq_const_safe!($T::MAX.carrying_add(0, true), (0, true)); - assert_eq_const_safe!($T::MAX.carrying_add(1, true), (1, true)); - - assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); - assert_eq_const_safe!($T::MIN.carrying_add(0, true), (1, false)); - assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, true), (0, true)); - } - - fn test_borrowing_sub() { - assert_eq_const_safe!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); - assert_eq_const_safe!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); - assert_eq_const_safe!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); - - assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); - assert_eq_const_safe!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); - assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); - } - - fn test_widening_mul() { - assert_eq_const_safe!($T::MAX.widening_mul($T::MAX), (1, $T::MAX - 1)); - } - - fn test_carrying_mul() { - assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, 0), (1, $T::MAX - 1)); - assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, $T::MAX), (0, $T::MAX)); - } - - fn test_carrying_mul_add() { - assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, 0, 0), (1, $T::MAX - 1)); - assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, 0), (0, $T::MAX)); - assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, $T::MAX), ($T::MAX, $T::MAX)); - } - - fn test_midpoint() { - assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); - assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); - - assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); - assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); - assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); - assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); - - assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); - assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); - assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); - assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); - - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); - - assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3); - assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); - } - } - }; -} diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs deleted file mode 100644 index 0b9fca8455b..00000000000 --- a/library/core/tests/num/wrapping.rs +++ /dev/null @@ -1,316 +0,0 @@ -use core::num::Wrapping; - -macro_rules! wrapping_operation { - ($result:expr, $lhs:ident $op:tt $rhs:expr) => { - assert_eq!($result, $lhs $op $rhs); - assert_eq!($result, &$lhs $op $rhs); - assert_eq!($result, $lhs $op &$rhs); - assert_eq!($result, &$lhs $op &$rhs); - }; - ($result:expr, $op:tt $expr:expr) => { - assert_eq!($result, $op $expr); - assert_eq!($result, $op &$expr); - }; -} - -macro_rules! wrapping_assignment { - ($result:expr, $lhs:ident $op:tt $rhs:expr) => { - let mut lhs1 = $lhs; - lhs1 $op $rhs; - assert_eq!($result, lhs1); - - let mut lhs2 = $lhs; - lhs2 $op &$rhs; - assert_eq!($result, lhs2); - }; -} - -macro_rules! wrapping_test { - ($fn_name:ident, $type:ty, $min:expr, $max:expr) => { - #[test] - fn $fn_name() { - let zero: Wrapping<$type> = Wrapping(0); - let one: Wrapping<$type> = Wrapping(1); - let min: Wrapping<$type> = Wrapping($min); - let max: Wrapping<$type> = Wrapping($max); - - wrapping_operation!(min, max + one); - wrapping_assignment!(min, max += one); - wrapping_operation!(max, min - one); - wrapping_assignment!(max, min -= one); - wrapping_operation!(max, max * one); - wrapping_assignment!(max, max *= one); - wrapping_operation!(max, max / one); - wrapping_assignment!(max, max /= one); - wrapping_operation!(zero, max % one); - wrapping_assignment!(zero, max %= one); - wrapping_operation!(zero, zero & max); - wrapping_assignment!(zero, zero &= max); - wrapping_operation!(max, zero | max); - wrapping_assignment!(max, zero |= max); - wrapping_operation!(zero, max ^ max); - wrapping_assignment!(zero, max ^= max); - wrapping_operation!(zero, zero << 1usize); - wrapping_assignment!(zero, zero <<= 1usize); - wrapping_operation!(zero, zero >> 1usize); - wrapping_assignment!(zero, zero >>= 1usize); - wrapping_operation!(zero, -zero); - wrapping_operation!(max, !min); - } - }; -} - -wrapping_test!(test_wrapping_i8, i8, i8::MIN, i8::MAX); -wrapping_test!(test_wrapping_i16, i16, i16::MIN, i16::MAX); -wrapping_test!(test_wrapping_i32, i32, i32::MIN, i32::MAX); -wrapping_test!(test_wrapping_i64, i64, i64::MIN, i64::MAX); -wrapping_test!(test_wrapping_i128, i128, i128::MIN, i128::MAX); -wrapping_test!(test_wrapping_isize, isize, isize::MIN, isize::MAX); -wrapping_test!(test_wrapping_u8, u8, u8::MIN, u8::MAX); -wrapping_test!(test_wrapping_u16, u16, u16::MIN, u16::MAX); -wrapping_test!(test_wrapping_u32, u32, u32::MIN, u32::MAX); -wrapping_test!(test_wrapping_u64, u64, u64::MIN, u64::MAX); -wrapping_test!(test_wrapping_u128, u128, u128::MIN, u128::MAX); -wrapping_test!(test_wrapping_usize, usize, usize::MIN, usize::MAX); - -#[test] -fn wrapping_int_api() { - assert_eq!(i8::MAX.wrapping_add(1), i8::MIN); - assert_eq!(i16::MAX.wrapping_add(1), i16::MIN); - assert_eq!(i32::MAX.wrapping_add(1), i32::MIN); - assert_eq!(i64::MAX.wrapping_add(1), i64::MIN); - assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); - - assert_eq!(i8::MIN.wrapping_sub(1), i8::MAX); - assert_eq!(i16::MIN.wrapping_sub(1), i16::MAX); - assert_eq!(i32::MIN.wrapping_sub(1), i32::MAX); - assert_eq!(i64::MIN.wrapping_sub(1), i64::MAX); - assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); - - assert_eq!(u8::MAX.wrapping_add(1), u8::MIN); - assert_eq!(u16::MAX.wrapping_add(1), u16::MIN); - assert_eq!(u32::MAX.wrapping_add(1), u32::MIN); - assert_eq!(u64::MAX.wrapping_add(1), u64::MIN); - assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); - - assert_eq!(u8::MIN.wrapping_sub(1), u8::MAX); - assert_eq!(u16::MIN.wrapping_sub(1), u16::MAX); - assert_eq!(u32::MIN.wrapping_sub(1), u32::MAX); - assert_eq!(u64::MIN.wrapping_sub(1), u64::MAX); - assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); - - assert_eq!((0xfe_u8 as i8).wrapping_mul(16), (0xe0_u8 as i8)); - assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), (0xedc0_u16 as i16)); - assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), (0xedcb_a980_u32 as i32)); - assert_eq!( - (0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as i64) - ); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), (0xedcb_a980_u32 as isize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!( - (0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as isize) - ); - } - } - - assert_eq!((0xfe as u8).wrapping_mul(16), (0xe0 as u8)); - assert_eq!((0xfedc as u16).wrapping_mul(16), (0xedc0 as u16)); - assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), (0xedcb_a980 as u32)); - assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), (0xedcb_a987_6543_2170 as u64)); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), (0xedcb_a980 as usize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!( - (0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), - (0xedcb_a987_6543_2170 as usize) - ); - } - } - - macro_rules! check_mul_no_wrap { - ($e:expr, $f:expr) => { - assert_eq!(($e).wrapping_mul($f), ($e) * $f); - }; - } - macro_rules! check_mul_wraps { - ($e:expr, $f:expr) => { - assert_eq!(($e).wrapping_mul($f), $e); - }; - } - - check_mul_no_wrap!(0xfe_u8 as i8, -1); - check_mul_no_wrap!(0xfedc_u16 as i16, -1); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_mul_no_wrap!(0xfe_u8 as i8, -2); - check_mul_no_wrap!(0xfedc_u16 as i16, -2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); - - check_mul_no_wrap!(0xfe_u8 as i8, 2); - check_mul_no_wrap!(0xfedc_u16 as i16, 2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); - - check_mul_wraps!(0x80_u8 as i8, -1); - check_mul_wraps!(0x8000_u16 as i16, -1); - check_mul_wraps!(0x8000_0000_u32 as i32, -1); - check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_mul_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_div_no_wrap { - ($e:expr, $f:expr) => { - assert_eq!(($e).wrapping_div($f), ($e) / $f); - }; - } - macro_rules! check_div_wraps { - ($e:expr, $f:expr) => { - assert_eq!(($e).wrapping_div($f), $e); - }; - } - - check_div_no_wrap!(0xfe_u8 as i8, -1); - check_div_no_wrap!(0xfedc_u16 as i16, -1); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_div_no_wrap!(0xfe_u8 as i8, -2); - check_div_no_wrap!(0xfedc_u16 as i16, -2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_div_no_wrap!(0xfe_u8 as i8, 2); - check_div_no_wrap!(0xfedc_u16 as i16, 2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_div_wraps!(-128 as i8, -1); - check_div_wraps!(0x8000_u16 as i16, -1); - check_div_wraps!(0x8000_0000_u32 as i32, -1); - check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_div_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_rem_no_wrap { - ($e:expr, $f:expr) => { - assert_eq!(($e).wrapping_rem($f), ($e) % $f); - }; - } - macro_rules! check_rem_wraps { - ($e:expr, $f:expr) => { - assert_eq!(($e).wrapping_rem($f), 0); - }; - } - - check_rem_no_wrap!(0xfe_u8 as i8, -1); - check_rem_no_wrap!(0xfedc_u16 as i16, -1); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_rem_no_wrap!(0xfe_u8 as i8, -2); - check_rem_no_wrap!(0xfedc_u16 as i16, -2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_rem_no_wrap!(0xfe_u8 as i8, 2); - check_rem_no_wrap!(0xfedc_u16 as i16, 2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_rem_wraps!(0x80_u8 as i8, -1); - check_rem_wraps!(0x8000_u16 as i16, -1); - check_rem_wraps!(0x8000_0000_u32 as i32, -1); - check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_rem_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_neg_no_wrap { - ($e:expr) => { - assert_eq!(($e).wrapping_neg(), -($e)); - }; - } - macro_rules! check_neg_wraps { - ($e:expr) => { - assert_eq!(($e).wrapping_neg(), ($e)); - }; - } - - check_neg_no_wrap!(0xfe_u8 as i8); - check_neg_no_wrap!(0xfedc_u16 as i16); - check_neg_no_wrap!(0xfedc_ba98_u32 as i32); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); - - check_neg_wraps!(0x80_u8 as i8); - check_neg_wraps!(0x8000_u16 as i16); - check_neg_wraps!(0x8000_0000_u32 as i32); - check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_neg_wraps!(0x8000_0000_u32 as isize); - } - #[cfg(target_pointer_width = "64")] - () => { - check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); - } - } -} - -#[test] -fn wrapping_const() { - // Specifically the wrapping behavior of division and remainder is subtle, - // see https://github.com/rust-lang/rust/pull/94512. - const _: () = { - assert!(i32::MIN.wrapping_div(-1) == i32::MIN); - assert!(i32::MIN.wrapping_rem(-1) == 0); - }; -} diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs deleted file mode 100644 index 501e0f33fe4..00000000000 --- a/library/core/tests/ops.rs +++ /dev/null @@ -1,242 +0,0 @@ -mod control_flow; -mod from_residual; - -use core::ops::{ - Bound, Deref, DerefMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, -}; - -// Test the Range structs and syntax. - -#[test] -fn test_range() { - let r = Range { start: 2, end: 10 }; - let mut count = 0; - for (i, ri) in r.enumerate() { - assert_eq!(ri, i + 2); - assert!(ri >= 2 && ri < 10); - count += 1; - } - assert_eq!(count, 8); -} - -#[test] -fn test_range_from() { - let r = RangeFrom { start: 2 }; - let mut count = 0; - for (i, ri) in r.take(10).enumerate() { - assert_eq!(ri, i + 2); - assert!(ri >= 2 && ri < 12); - count += 1; - } - assert_eq!(count, 10); -} - -#[test] -fn test_range_to() { - // Not much to test. - let _ = RangeTo { end: 42 }; -} - -#[test] -fn test_full_range() { - // Not much to test. - let _ = RangeFull; -} - -#[test] -fn test_range_inclusive() { - let mut r = RangeInclusive::new(1i8, 2); - assert_eq!(r.next(), Some(1)); - assert_eq!(r.next(), Some(2)); - assert_eq!(r.next(), None); - - r = RangeInclusive::new(127i8, 127); - assert_eq!(r.next(), Some(127)); - assert_eq!(r.next(), None); - - r = RangeInclusive::new(-128i8, -128); - assert_eq!(r.next_back(), Some(-128)); - assert_eq!(r.next_back(), None); - - // degenerate - r = RangeInclusive::new(1, -1); - assert_eq!(r.size_hint(), (0, Some(0))); - assert_eq!(r.next(), None); -} - -#[test] -fn test_range_to_inclusive() { - // Not much to test. - let _ = RangeToInclusive { end: 42 }; -} - -#[test] -fn test_range_is_empty() { - assert!(!(0.0..10.0).is_empty()); - assert!((-0.0..0.0).is_empty()); - assert!((10.0..0.0).is_empty()); - - assert!(!(f32::NEG_INFINITY..f32::INFINITY).is_empty()); - assert!((f32::EPSILON..f32::NAN).is_empty()); - assert!((f32::NAN..f32::EPSILON).is_empty()); - assert!((f32::NAN..f32::NAN).is_empty()); - - assert!(!(0.0..=10.0).is_empty()); - assert!(!(-0.0..=0.0).is_empty()); - assert!((10.0..=0.0).is_empty()); - - assert!(!(f32::NEG_INFINITY..=f32::INFINITY).is_empty()); - assert!((f32::EPSILON..=f32::NAN).is_empty()); - assert!((f32::NAN..=f32::EPSILON).is_empty()); - assert!((f32::NAN..=f32::NAN).is_empty()); -} - -#[test] -fn test_bound_cloned_unbounded() { - assert_eq!(Bound::<&u32>::Unbounded.cloned(), Bound::Unbounded); -} - -#[test] -fn test_bound_cloned_included() { - assert_eq!(Bound::Included(&3).cloned(), Bound::Included(3)); -} - -#[test] -fn test_bound_cloned_excluded() { - assert_eq!(Bound::Excluded(&3).cloned(), Bound::Excluded(3)); -} - -#[test] -#[allow(unused_comparisons)] -#[allow(unused_mut)] -fn test_range_syntax() { - let mut count = 0; - for i in 0_usize..10 { - assert!(i >= 0 && i < 10); - count += i; - } - assert_eq!(count, 45); - - let mut count = 0; - let mut range = 0_usize..10; - for i in range { - assert!(i >= 0 && i < 10); - count += i; - } - assert_eq!(count, 45); - - let mut count = 0; - let mut rf = 3_usize..; - for i in rf.take(10) { - assert!(i >= 3 && i < 13); - count += i; - } - assert_eq!(count, 75); - - let _ = 0_usize..4 + 4 - 3; - - fn foo() -> isize { - 42 - } - let _ = 0..foo(); - - let _ = { &42..&100 }; // references to literals are OK - let _ = ..42_usize; - - // Test we can use two different types with a common supertype. - let x = &42; - { - let y = 42; - let _ = x..&y; - } -} - -#[test] -#[allow(dead_code)] -fn test_range_syntax_in_return_statement() { - fn return_range_to() -> RangeTo { - return ..1; - } - fn return_full_range() -> RangeFull { - return ..; - } - // Not much to test. -} - -#[test] -fn range_structural_match() { - // test that all range types can be structurally matched upon - - const RANGE: Range = 0..1000; - match RANGE { - RANGE => {} - _ => unreachable!(), - } - - const RANGE_FROM: RangeFrom = 0..; - match RANGE_FROM { - RANGE_FROM => {} - _ => unreachable!(), - } - - const RANGE_FULL: RangeFull = ..; - match RANGE_FULL { - RANGE_FULL => {} - } - - const RANGE_INCLUSIVE: RangeInclusive = 0..=999; - match RANGE_INCLUSIVE { - RANGE_INCLUSIVE => {} - _ => unreachable!(), - } - - const RANGE_TO: RangeTo = ..1000; - match RANGE_TO { - RANGE_TO => {} - _ => unreachable!(), - } - - const RANGE_TO_INCLUSIVE: RangeToInclusive = ..=999; - match RANGE_TO_INCLUSIVE { - RANGE_TO_INCLUSIVE => {} - _ => unreachable!(), - } -} - -// Test Deref implementations - -#[test] -fn deref_mut_on_ref() { - // Test that `&mut T` implements `DerefMut` - - fn inc + DerefMut>(mut t: T) { - *t += 1; - } - - let mut x: isize = 5; - inc(&mut x); - assert_eq!(x, 6); -} - -#[test] -fn deref_on_ref() { - // Test that `&T` and `&mut T` implement `Deref` - - fn deref>(t: T) -> U { - *t - } - - let x: isize = 3; - let y = deref(&x); - assert_eq!(y, 3); - - let mut x: isize = 4; - let y = deref(&mut x); - assert_eq!(y, 4); -} - -#[test] -#[allow(unreachable_code)] -fn test_not_never() { - if !return () {} -} diff --git a/library/core/tests/ops/control_flow.rs b/library/core/tests/ops/control_flow.rs deleted file mode 100644 index eacfd63a6c4..00000000000 --- a/library/core/tests/ops/control_flow.rs +++ /dev/null @@ -1,18 +0,0 @@ -use core::intrinsics::discriminant_value; -use core::ops::ControlFlow; - -#[test] -fn control_flow_discriminants_match_result() { - // This isn't stable surface area, but helps keep `?` cheap between them, - // even if LLVM can't always take advantage of it right now. - // (Sadly Result and Option are inconsistent, so ControlFlow can't match both.) - - assert_eq!( - discriminant_value(&ControlFlow::::Break(3)), - discriminant_value(&Result::::Err(3)), - ); - assert_eq!( - discriminant_value(&ControlFlow::::Continue(3)), - discriminant_value(&Result::::Ok(3)), - ); -} diff --git a/library/core/tests/ops/from_residual.rs b/library/core/tests/ops/from_residual.rs deleted file mode 100644 index d5c86ccbcd3..00000000000 --- a/library/core/tests/ops/from_residual.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Regression test that Option and ControlFlow can have downstream FromResidual impls. -//! cc https://github.com/rust-lang/rust/issues/99940, -//! This does NOT test that issue in general; Option and ControlFlow's FromResidual -//! impls in core were changed to not be affected by that issue. - -use core::ops::{ControlFlow, FromResidual}; - -struct Local; - -impl FromResidual for Option { - fn from_residual(_: Local) -> Option { - unimplemented!() - } -} - -impl FromResidual for ControlFlow { - fn from_residual(_: Local) -> ControlFlow { - unimplemented!() - } -} - -impl FromResidual for Result { - fn from_residual(_: Local) -> Result { - unimplemented!() - } -} diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs deleted file mode 100644 index 336a79a02ce..00000000000 --- a/library/core/tests/option.rs +++ /dev/null @@ -1,586 +0,0 @@ -use core::cell::Cell; -use core::mem; -use core::ops::DerefMut; -use core::option::*; - -#[test] -fn test_get_ptr() { - unsafe { - let x: Box<_> = Box::new(0); - let addr_x: *const isize = mem::transmute(&*x); - let opt = Some(x); - let y = opt.unwrap(); - let addr_y: *const isize = mem::transmute(&*y); - assert_eq!(addr_x, addr_y); - } -} - -#[test] -fn test_get_str() { - let x = "test".to_string(); - let addr_x = x.as_ptr(); - let opt = Some(x); - let y = opt.unwrap(); - let addr_y = y.as_ptr(); - assert_eq!(addr_x, addr_y); -} - -#[test] -fn test_get_resource() { - use core::cell::RefCell; - use std::rc::Rc; - - struct R { - i: Rc>, - } - - impl Drop for R { - fn drop(&mut self) { - let ii = &*self.i; - let i = *ii.borrow(); - *ii.borrow_mut() = i + 1; - } - } - - fn r(i: Rc>) -> R { - R { i } - } - - let i = Rc::new(RefCell::new(0)); - { - let x = r(i.clone()); - let opt = Some(x); - let _y = opt.unwrap(); - } - assert_eq!(*i.borrow(), 1); -} - -#[test] -#[allow(for_loops_over_fallibles)] -fn test_option_dance() { - let x = Some(()); - let mut y = Some(5); - let mut y2 = 0; - for _x in x { - y2 = y.take().unwrap(); - } - assert_eq!(y2, 5); - assert!(y.is_none()); -} - -#[test] -#[should_panic] -fn test_option_too_much_dance() { - struct A; - let mut y = Some(A); - let _y2 = y.take().unwrap(); - let _y3 = y.take().unwrap(); -} - -#[test] -fn test_and() { - let x: Option = Some(1); - assert_eq!(x.and(Some(2)), Some(2)); - assert_eq!(x.and(None::), None); - - let x: Option = None; - assert_eq!(x.and(Some(2)), None); - assert_eq!(x.and(None::), None); - - /* FIXME(#110395) - const FOO: Option = Some(1); - const A: Option = FOO.and(Some(2)); - const B: Option = FOO.and(None); - assert_eq!(A, Some(2)); - assert_eq!(B, None); - - const BAR: Option = None; - const C: Option = BAR.and(Some(2)); - const D: Option = BAR.and(None); - assert_eq!(C, None); - assert_eq!(D, None); - */ -} - -#[test] -fn test_and_then() { - const fn plus_one(x: isize) -> Option { - Some(x + 1) - } - - const fn none(_: isize) -> Option { - None - } - - let x: Option = Some(1); - assert_eq!(x.and_then(plus_one), Some(2)); - assert_eq!(x.and_then(none), None); - - let x: Option = None; - assert_eq!(x.and_then(plus_one), None); - assert_eq!(x.and_then(none), None); - - /* FIXME(#110395) - const FOO: Option = Some(1); - const A: Option = FOO.and_then(plus_one); - const B: Option = FOO.and_then(none); - assert_eq!(A, Some(2)); - assert_eq!(B, None); - - const BAR: Option = None; - const C: Option = BAR.and_then(plus_one); - const D: Option = BAR.and_then(none); - assert_eq!(C, None); - assert_eq!(D, None); - */ -} - -#[test] -fn test_or() { - let x: Option = Some(1); - assert_eq!(x.or(Some(2)), Some(1)); - assert_eq!(x.or(None), Some(1)); - - let x: Option = None; - assert_eq!(x.or(Some(2)), Some(2)); - assert_eq!(x.or(None), None); - - /* FIXME(#110395) - const FOO: Option = Some(1); - const A: Option = FOO.or(Some(2)); - const B: Option = FOO.or(None); - assert_eq!(A, Some(1)); - assert_eq!(B, Some(1)); - - const BAR: Option = None; - const C: Option = BAR.or(Some(2)); - const D: Option = BAR.or(None); - assert_eq!(C, Some(2)); - assert_eq!(D, None); - */ -} - -#[test] -fn test_or_else() { - const fn two() -> Option { - Some(2) - } - - const fn none() -> Option { - None - } - - let x: Option = Some(1); - assert_eq!(x.or_else(two), Some(1)); - assert_eq!(x.or_else(none), Some(1)); - - let x: Option = None; - assert_eq!(x.or_else(two), Some(2)); - assert_eq!(x.or_else(none), None); - - /* FIXME(#110395) - const FOO: Option = Some(1); - const A: Option = FOO.or_else(two); - const B: Option = FOO.or_else(none); - assert_eq!(A, Some(1)); - assert_eq!(B, Some(1)); - - const BAR: Option = None; - const C: Option = BAR.or_else(two); - const D: Option = BAR.or_else(none); - assert_eq!(C, Some(2)); - assert_eq!(D, None); - */ -} - -#[test] -fn test_unwrap() { - assert_eq!(Some(1).unwrap(), 1); - let s = Some("hello".to_string()).unwrap(); - assert_eq!(s, "hello"); -} - -#[test] -#[should_panic] -fn test_unwrap_panic1() { - let x: Option = None; - x.unwrap(); -} - -#[test] -#[should_panic] -fn test_unwrap_panic2() { - let x: Option = None; - x.unwrap(); -} - -#[test] -fn test_unwrap_or() { - let x: Option = Some(1); - assert_eq!(x.unwrap_or(2), 1); - - let x: Option = None; - assert_eq!(x.unwrap_or(2), 2); - - /* FIXME(#110395) - const A: isize = Some(1).unwrap_or(2); - const B: isize = None.unwrap_or(2); - assert_eq!(A, 1); - assert_eq!(B, 2); - */ -} - -#[test] -fn test_unwrap_or_else() { - const fn two() -> isize { - 2 - } - - let x: Option = Some(1); - assert_eq!(x.unwrap_or_else(two), 1); - - let x: Option = None; - assert_eq!(x.unwrap_or_else(two), 2); - - /* FIXME(#110395) - const A: isize = Some(1).unwrap_or_else(two); - const B: isize = None.unwrap_or_else(two); - assert_eq!(A, 1); - assert_eq!(B, 2); - */ -} - -#[test] -fn test_unwrap_unchecked() { - assert_eq!(unsafe { Some(1).unwrap_unchecked() }, 1); - let s = unsafe { Some("hello".to_string()).unwrap_unchecked() }; - assert_eq!(s, "hello"); -} - -#[test] -fn test_iter() { - let val = 5; - - let x = Some(val); - let mut it = x.iter(); - - assert_eq!(it.size_hint(), (1, Some(1))); - assert_eq!(it.next(), Some(&val)); - assert_eq!(it.size_hint(), (0, Some(0))); - assert!(it.next().is_none()); - - let mut it = (&x).into_iter(); - assert_eq!(it.next(), Some(&val)); -} - -#[test] -fn test_mut_iter() { - let mut val = 5; - let new_val = 11; - - let mut x = Some(val); - { - let mut it = x.iter_mut(); - - assert_eq!(it.size_hint(), (1, Some(1))); - - match it.next() { - Some(interior) => { - assert_eq!(*interior, val); - *interior = new_val; - } - None => assert!(false), - } - - assert_eq!(it.size_hint(), (0, Some(0))); - assert!(it.next().is_none()); - } - assert_eq!(x, Some(new_val)); - - let mut y = Some(val); - let mut it = (&mut y).into_iter(); - assert_eq!(it.next(), Some(&mut val)); -} - -#[test] -fn test_ord() { - let small = Some(1.0f64); - let big = Some(5.0f64); - let nan = Some(0.0f64 / 0.0); - assert!(!(nan < big)); - assert!(!(nan > big)); - assert!(small < big); - assert!(None < big); - assert!(big > None); -} - -#[test] -fn test_collect() { - let v: Option> = (0..0).map(|_| Some(0)).collect(); - assert!(v == Some(vec![])); - - let v: Option> = (0..3).map(|x| Some(x)).collect(); - assert!(v == Some(vec![0, 1, 2])); - - let v: Option> = (0..3).map(|x| if x > 1 { None } else { Some(x) }).collect(); - assert!(v == None); - - // test that it does not take more elements than it needs - let mut functions: [Box Option<()>>; 3] = - [Box::new(|| Some(())), Box::new(|| None), Box::new(|| panic!())]; - - let v: Option> = functions.iter_mut().map(|f| (*f)()).collect(); - - assert!(v == None); -} - -#[test] -fn test_copied() { - let val = 1; - let val_ref = &val; - let opt_none: Option<&'static u32> = None; - let opt_ref = Some(&val); - let opt_ref_ref = Some(&val_ref); - - // None works - assert_eq!(opt_none.clone(), None); - assert_eq!(opt_none.copied(), None); - - // Immutable ref works - assert_eq!(opt_ref.clone(), Some(&val)); - assert_eq!(opt_ref.copied(), Some(1)); - - // Double Immutable ref works - assert_eq!(opt_ref_ref.clone(), Some(&val_ref)); - assert_eq!(opt_ref_ref.clone().copied(), Some(&val)); - assert_eq!(opt_ref_ref.copied().copied(), Some(1)); -} - -#[test] -fn test_cloned() { - let val = 1; - let val_ref = &val; - let opt_none: Option<&'static u32> = None; - let opt_ref = Some(&val); - let opt_ref_ref = Some(&val_ref); - - // None works - assert_eq!(opt_none.clone(), None); - assert_eq!(opt_none.cloned(), None); - - // Immutable ref works - assert_eq!(opt_ref.clone(), Some(&val)); - assert_eq!(opt_ref.cloned(), Some(1)); - - // Double Immutable ref works - assert_eq!(opt_ref_ref.clone(), Some(&val_ref)); - assert_eq!(opt_ref_ref.clone().cloned(), Some(&val)); - assert_eq!(opt_ref_ref.cloned().cloned(), Some(1)); -} - -#[test] -fn test_try() { - fn try_option_some() -> Option { - let val = Some(1)?; - Some(val) - } - assert_eq!(try_option_some(), Some(1)); - - fn try_option_none() -> Option { - let val = None?; - Some(val) - } - assert_eq!(try_option_none(), None); -} - -#[test] -fn test_option_as_deref() { - // Some: &Option::Some(T) -> Option<&T::Deref::Target>::Some(&*T) - let ref_option = &Some(&42); - assert_eq!(ref_option.as_deref(), Some(&42)); - - let ref_option = &Some(String::from("a result")); - assert_eq!(ref_option.as_deref(), Some("a result")); - - let ref_option = &Some(vec![1, 2, 3, 4, 5]); - assert_eq!(ref_option.as_deref(), Some([1, 2, 3, 4, 5].as_slice())); - - // None: &Option>::None -> None - let ref_option: &Option<&i32> = &None; - assert_eq!(ref_option.as_deref(), None); -} - -#[test] -fn test_option_as_deref_mut() { - // Some: &mut Option::Some(T) -> Option<&mut T::Deref::Target>::Some(&mut *T) - let mut val = 42; - let ref_option = &mut Some(&mut val); - assert_eq!(ref_option.as_deref_mut(), Some(&mut 42)); - - let ref_option = &mut Some(String::from("a result")); - assert_eq!(ref_option.as_deref_mut(), Some(String::from("a result").deref_mut())); - - let ref_option = &mut Some(vec![1, 2, 3, 4, 5]); - assert_eq!(ref_option.as_deref_mut(), Some([1, 2, 3, 4, 5].as_mut_slice())); - - // None: &mut Option>::None -> None - let ref_option: &mut Option<&mut i32> = &mut None; - assert_eq!(ref_option.as_deref_mut(), None); -} - -#[test] -fn test_replace() { - let mut x = Some(2); - let old = x.replace(5); - - assert_eq!(x, Some(5)); - assert_eq!(old, Some(2)); - - let mut x = None; - let old = x.replace(3); - - assert_eq!(x, Some(3)); - assert_eq!(old, None); -} - -#[test] -fn option_const() { - // test that the methods of `Option` are usable in a const context - - const OPTION: Option = Some(32); - assert_eq!(OPTION, Some(32)); - - // FIXME(#110395) - // const OPTION_FROM: Option = Option::from(32); - // assert_eq!(OPTION_FROM, Some(32)); - - const REF: Option<&usize> = OPTION.as_ref(); - assert_eq!(REF, Some(&32)); - - // const REF_FROM: Option<&usize> = Option::from(&OPTION); - // assert_eq!(REF_FROM, Some(&32)); - - const IS_SOME: bool = OPTION.is_some(); - assert!(IS_SOME); - - const IS_NONE: bool = OPTION.is_none(); - assert!(!IS_NONE); - - const COPIED: Option = OPTION.as_ref().copied(); - assert_eq!(COPIED, OPTION); -} - -#[test] -const fn option_const_mut() { - // test that the methods of `Option` that take mutable references are usable in a const context - - let mut option: Option = Some(32); - - let _take = option.take(); - let _replace = option.replace(42); - - { - let as_mut = option.as_mut(); - match as_mut { - Some(v) => *v = 32, - None => unreachable!(), - } - } - /* FIXME(const-hack) - { - let as_mut: Option<&mut usize> = Option::from(&mut option); - match as_mut { - Some(v) => *v = 42, - None => unreachable!(), - } - } - */ -} - -#[test] -fn test_unwrap_drop() { - struct Dtor<'a> { - x: &'a Cell, - } - - impl<'a> std::ops::Drop for Dtor<'a> { - fn drop(&mut self) { - self.x.set(self.x.get() - 1); - } - } - - fn unwrap(o: Option) -> T { - match o { - Some(v) => v, - None => panic!(), - } - } - - let x = &Cell::new(1); - - { - let b = Some(Dtor { x }); - let _c = unwrap(b); - } - - assert_eq!(x.get(), 0); -} - -#[test] -fn option_ext() { - let thing = "{{ f }}"; - let f = thing.find("{{"); - - if f.is_none() { - println!("None!"); - } -} - -#[test] -fn zip_options() { - let x = Some(10); - let y = Some("foo"); - let z: Option = None; - - assert_eq!(x.zip(y), Some((10, "foo"))); - assert_eq!(x.zip(z), None); - assert_eq!(z.zip(x), None); -} - -#[test] -fn unzip_options() { - let x = Some((10, "foo")); - let y = None::<(bool, i32)>; - - assert_eq!(x.unzip(), (Some(10), Some("foo"))); - assert_eq!(y.unzip(), (None, None)); -} - -#[test] -fn zip_unzip_roundtrip() { - let x = Some(10); - let y = Some("foo"); - - let z = x.zip(y); - assert_eq!(z, Some((10, "foo"))); - - let a = z.unzip(); - assert_eq!(a, (x, y)); -} - -#[test] -fn as_slice() { - assert_eq!(Some(42).as_slice(), &[42]); - assert_eq!(Some(43).as_mut_slice(), &[43]); - assert_eq!(None::.as_slice(), &[]); - assert_eq!(None::.as_mut_slice(), &[]); - - const A: &[u32] = Some(44).as_slice(); - const B: &[u32] = None.as_slice(); - const _: () = { - let [45] = Some(45).as_mut_slice() else { panic!() }; - let []: &[u32] = None.as_mut_slice() else { panic!() }; - }; - assert_eq!(A, &[44]); - assert_eq!(B, &[]); -} diff --git a/library/core/tests/panic.rs b/library/core/tests/panic.rs deleted file mode 100644 index 24b6c56b356..00000000000 --- a/library/core/tests/panic.rs +++ /dev/null @@ -1 +0,0 @@ -mod location; diff --git a/library/core/tests/panic/location.rs b/library/core/tests/panic/location.rs deleted file mode 100644 index d20241d8380..00000000000 --- a/library/core/tests/panic/location.rs +++ /dev/null @@ -1,31 +0,0 @@ -use core::panic::Location; - -// Note: Some of the following tests depend on the source location, -// so please be careful when editing this file. - -#[test] -fn location_const_caller() { - const _CALLER_REFERENCE: &Location<'static> = Location::caller(); - const _CALLER: Location<'static> = *Location::caller(); -} - -#[test] -fn location_const_file() { - const CALLER: &Location<'static> = Location::caller(); - const FILE: &str = CALLER.file(); - assert_eq!(FILE, file!()); -} - -#[test] -fn location_const_line() { - const CALLER: &Location<'static> = Location::caller(); - const LINE: u32 = CALLER.line(); - assert_eq!(LINE, 21); -} - -#[test] -fn location_const_column() { - const CALLER: &Location<'static> = Location::caller(); - const COLUMN: u32 = CALLER.column(); - assert_eq!(COLUMN, 40); -} diff --git a/library/core/tests/pattern.rs b/library/core/tests/pattern.rs deleted file mode 100644 index d4bec996d89..00000000000 --- a/library/core/tests/pattern.rs +++ /dev/null @@ -1,503 +0,0 @@ -use std::str::pattern::*; - -// This macro makes it easier to write -// tests that do a series of iterations -macro_rules! search_asserts { - ($haystack:expr, $needle:expr, $testname:expr, [$($func:ident),*], $result:expr) => { - let mut searcher = $needle.into_searcher($haystack); - let arr = [$( Step::from(searcher.$func()) ),*]; - assert_eq!(&arr[..], &$result, $testname); - } -} - -/// Combined enum for the results of next() and next_match()/next_reject() -#[derive(Debug, PartialEq, Eq)] -enum Step { - // variant names purposely chosen to - // be the same length for easy alignment - Matches(usize, usize), - Rejects(usize, usize), - InRange(usize, usize), - Done, -} - -use self::Step::*; - -impl From for Step { - fn from(x: SearchStep) -> Self { - match x { - SearchStep::Match(a, b) => Matches(a, b), - SearchStep::Reject(a, b) => Rejects(a, b), - SearchStep::Done => Done, - } - } -} - -impl From> for Step { - fn from(x: Option<(usize, usize)>) -> Self { - match x { - Some((a, b)) => InRange(a, b), - None => Done, - } - } -} - -// FIXME(Manishearth) these tests focus on single-character searching (CharSearcher) -// and on next()/next_match(), not next_reject(). This is because -// the memchr changes make next_match() for single chars complex, but next_reject() -// continues to use next() under the hood. We should add more test cases for all -// of these, as well as tests for StrSearcher and higher level tests for str::find() (etc) - -#[test] -fn test_simple_iteration() { - search_asserts!( - "abcdeabcd", - 'a', - "forward iteration for ASCII string", - // a b c d e a b c d EOF - [next, next, next, next, next, next, next, next, next, next], - [ - Matches(0, 1), - Rejects(1, 2), - Rejects(2, 3), - Rejects(3, 4), - Rejects(4, 5), - Matches(5, 6), - Rejects(6, 7), - Rejects(7, 8), - Rejects(8, 9), - Done - ] - ); - - search_asserts!( - "abcdeabcd", - 'a', - "reverse iteration for ASCII string", - // d c b a e d c b a EOF - [ - next_back, next_back, next_back, next_back, next_back, next_back, next_back, next_back, - next_back, next_back - ], - [ - Rejects(8, 9), - Rejects(7, 8), - Rejects(6, 7), - Matches(5, 6), - Rejects(4, 5), - Rejects(3, 4), - Rejects(2, 3), - Rejects(1, 2), - Matches(0, 1), - Done - ] - ); - - search_asserts!( - "我爱我的猫", - '我', - "forward iteration for Chinese string", - // 我 愛 我 的 貓 EOF - [next, next, next, next, next, next], - [Matches(0, 3), Rejects(3, 6), Matches(6, 9), Rejects(9, 12), Rejects(12, 15), Done] - ); - - search_asserts!( - "我的猫说meow", - 'm', - "forward iteration for mixed string", - // 我 的 猫 说 m e o w EOF - [next, next, next, next, next, next, next, next, next], - [ - Rejects(0, 3), - Rejects(3, 6), - Rejects(6, 9), - Rejects(9, 12), - Matches(12, 13), - Rejects(13, 14), - Rejects(14, 15), - Rejects(15, 16), - Done - ] - ); - - search_asserts!( - "我的猫说meow", - '猫', - "reverse iteration for mixed string", - // w o e m 说 猫 的 我 EOF - [ - next_back, next_back, next_back, next_back, next_back, next_back, next_back, next_back, - next_back - ], - [ - Rejects(15, 16), - Rejects(14, 15), - Rejects(13, 14), - Rejects(12, 13), - Rejects(9, 12), - Matches(6, 9), - Rejects(3, 6), - Rejects(0, 3), - Done - ] - ); -} - -#[test] -fn test_simple_search() { - search_asserts!( - "abcdeabcdeabcde", - 'a', - "next_match for ASCII string", - [next_match, next_match, next_match, next_match], - [InRange(0, 1), InRange(5, 6), InRange(10, 11), Done] - ); - - search_asserts!( - "abcdeabcdeabcde", - 'a', - "next_match_back for ASCII string", - [next_match_back, next_match_back, next_match_back, next_match_back], - [InRange(10, 11), InRange(5, 6), InRange(0, 1), Done] - ); - - search_asserts!( - "abcdeab", - 'a', - "next_reject for ASCII string", - [next_reject, next_reject, next_match, next_reject, next_reject], - [InRange(1, 2), InRange(2, 3), InRange(5, 6), InRange(6, 7), Done] - ); - - search_asserts!( - "abcdeabcdeabcde", - 'a', - "next_reject_back for ASCII string", - [ - next_reject_back, - next_reject_back, - next_match_back, - next_reject_back, - next_reject_back, - next_reject_back - ], - [ - InRange(14, 15), - InRange(13, 14), - InRange(10, 11), - InRange(9, 10), - InRange(8, 9), - InRange(7, 8) - ] - ); -} - -// Á, 각, ก, 😀 all end in 0x81 -// 🁀, ᘀ do not end in 0x81 but contain the byte -// ꁁ has 0x81 as its second and third bytes. -// -// The memchr-using implementation of next_match -// and next_match_back temporarily violate -// the property that the search is always on a unicode boundary, -// which is fine as long as this never reaches next() or next_back(). -// So we test if next() is correct after each next_match() as well. -const STRESS: &str = "Áa🁀bÁꁁfg😁각กᘀ각aÁ각ꁁก😁a"; - -#[test] -fn test_stress_indices() { - // this isn't really a test, more of documentation on the indices of each character in the stresstest string - - search_asserts!( - STRESS, - 'x', - "Indices of characters in stress test", - [ - next, next, next, next, next, next, next, next, next, next, next, next, next, next, - next, next, next, next, next, next, next - ], - [ - Rejects(0, 2), // Á - Rejects(2, 3), // a - Rejects(3, 7), // 🁀 - Rejects(7, 8), // b - Rejects(8, 10), // Á - Rejects(10, 13), // ꁁ - Rejects(13, 14), // f - Rejects(14, 15), // g - Rejects(15, 19), // 😀 - Rejects(19, 22), // 각 - Rejects(22, 25), // ก - Rejects(25, 28), // ᘀ - Rejects(28, 31), // 각 - Rejects(31, 32), // a - Rejects(32, 34), // Á - Rejects(34, 37), // 각 - Rejects(37, 40), // ꁁ - Rejects(40, 43), // ก - Rejects(43, 47), // 😀 - Rejects(47, 48), // a - Done - ] - ); -} - -#[test] -fn test_forward_search_shared_bytes() { - search_asserts!( - STRESS, - 'Á', - "Forward search for two-byte Latin character", - [next_match, next_match, next_match, next_match], - [InRange(0, 2), InRange(8, 10), InRange(32, 34), Done] - ); - - search_asserts!( - STRESS, - 'Á', - "Forward search for two-byte Latin character; check if next() still works", - [next_match, next, next_match, next, next_match, next, next_match], - [ - InRange(0, 2), - Rejects(2, 3), - InRange(8, 10), - Rejects(10, 13), - InRange(32, 34), - Rejects(34, 37), - Done - ] - ); - - search_asserts!( - STRESS, - '각', - "Forward search for three-byte Hangul character", - [next_match, next, next_match, next_match, next_match], - [InRange(19, 22), Rejects(22, 25), InRange(28, 31), InRange(34, 37), Done] - ); - - search_asserts!( - STRESS, - '각', - "Forward search for three-byte Hangul character; check if next() still works", - [next_match, next, next_match, next, next_match, next, next_match], - [ - InRange(19, 22), - Rejects(22, 25), - InRange(28, 31), - Rejects(31, 32), - InRange(34, 37), - Rejects(37, 40), - Done - ] - ); - - search_asserts!( - STRESS, - 'ก', - "Forward search for three-byte Thai character", - [next_match, next, next_match, next, next_match], - [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done] - ); - - search_asserts!( - STRESS, - 'ก', - "Forward search for three-byte Thai character; check if next() still works", - [next_match, next, next_match, next, next_match], - [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done] - ); - - search_asserts!( - STRESS, - '😁', - "Forward search for four-byte emoji", - [next_match, next, next_match, next, next_match], - [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done] - ); - - search_asserts!( - STRESS, - '😁', - "Forward search for four-byte emoji; check if next() still works", - [next_match, next, next_match, next, next_match], - [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done] - ); - - search_asserts!( - STRESS, - 'ꁁ', - "Forward search for three-byte Yi character with repeated bytes", - [next_match, next, next_match, next, next_match], - [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done] - ); - - search_asserts!( - STRESS, - 'ꁁ', - "Forward search for three-byte Yi character with repeated bytes; check if next() still works", - [next_match, next, next_match, next, next_match], - [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done] - ); -} - -#[test] -fn test_reverse_search_shared_bytes() { - search_asserts!( - STRESS, - 'Á', - "Reverse search for two-byte Latin character", - [next_match_back, next_match_back, next_match_back, next_match_back], - [InRange(32, 34), InRange(8, 10), InRange(0, 2), Done] - ); - - search_asserts!( - STRESS, - 'Á', - "Reverse search for two-byte Latin character; check if next_back() still works", - [next_match_back, next_back, next_match_back, next_back, next_match_back, next_back], - [InRange(32, 34), Rejects(31, 32), InRange(8, 10), Rejects(7, 8), InRange(0, 2), Done] - ); - - search_asserts!( - STRESS, - '각', - "Reverse search for three-byte Hangul character", - [next_match_back, next_back, next_match_back, next_match_back, next_match_back], - [InRange(34, 37), Rejects(32, 34), InRange(28, 31), InRange(19, 22), Done] - ); - - search_asserts!( - STRESS, - '각', - "Reverse search for three-byte Hangul character; check if next_back() still works", - [ - next_match_back, - next_back, - next_match_back, - next_back, - next_match_back, - next_back, - next_match_back - ], - [ - InRange(34, 37), - Rejects(32, 34), - InRange(28, 31), - Rejects(25, 28), - InRange(19, 22), - Rejects(15, 19), - Done - ] - ); - - search_asserts!( - STRESS, - 'ก', - "Reverse search for three-byte Thai character", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done] - ); - - search_asserts!( - STRESS, - 'ก', - "Reverse search for three-byte Thai character; check if next_back() still works", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done] - ); - - search_asserts!( - STRESS, - '😁', - "Reverse search for four-byte emoji", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done] - ); - - search_asserts!( - STRESS, - '😁', - "Reverse search for four-byte emoji; check if next_back() still works", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done] - ); - - search_asserts!( - STRESS, - 'ꁁ', - "Reverse search for three-byte Yi character with repeated bytes", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done] - ); - - search_asserts!( - STRESS, - 'ꁁ', - "Reverse search for three-byte Yi character with repeated bytes; check if next_back() still works", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done] - ); -} - -#[test] -fn double_ended_regression_test() { - // https://github.com/rust-lang/rust/issues/47175 - // Ensures that double ended searching comes to a convergence - search_asserts!( - "abcdeabcdeabcde", - 'a', - "alternating double ended search", - [next_match, next_match_back, next_match, next_match_back], - [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done] - ); - search_asserts!( - "abcdeabcdeabcde", - 'a', - "triple double ended search for a", - [next_match, next_match_back, next_match_back, next_match_back], - [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done] - ); - search_asserts!( - "abcdeabcdeabcde", - 'd', - "triple double ended search for d", - [next_match, next_match_back, next_match_back, next_match_back], - [InRange(3, 4), InRange(13, 14), InRange(8, 9), Done] - ); - search_asserts!( - STRESS, - 'Á', - "Double ended search for two-byte Latin character", - [next_match, next_match_back, next_match, next_match_back], - [InRange(0, 2), InRange(32, 34), InRange(8, 10), Done] - ); - search_asserts!( - STRESS, - '각', - "Reverse double ended search for three-byte Hangul character", - [next_match_back, next_back, next_match, next, next_match_back, next_match], - [InRange(34, 37), Rejects(32, 34), InRange(19, 22), Rejects(22, 25), InRange(28, 31), Done] - ); - search_asserts!( - STRESS, - 'ก', - "Double ended search for three-byte Thai character", - [next_match, next_back, next, next_match_back, next_match], - [InRange(22, 25), Rejects(47, 48), Rejects(25, 28), InRange(40, 43), Done] - ); - search_asserts!( - STRESS, - '😁', - "Double ended search for four-byte emoji", - [next_match_back, next, next_match, next_back, next_match], - [InRange(43, 47), Rejects(0, 2), InRange(15, 19), Rejects(40, 43), Done] - ); - search_asserts!( - STRESS, - 'ꁁ', - "Double ended search for three-byte Yi character with repeated bytes", - [next_match, next, next_match_back, next_back, next_match], - [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(34, 37), Done] - ); -} diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs deleted file mode 100644 index 026d2ca8de2..00000000000 --- a/library/core/tests/pin.rs +++ /dev/null @@ -1,81 +0,0 @@ -use core::pin::Pin; - -#[test] -fn pin_const() { - // test that the methods of `Pin` are usable in a const context - - const POINTER: &'static usize = &2; - - const PINNED: Pin<&'static usize> = Pin::new(POINTER); - const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) }; - assert_eq!(PINNED_UNCHECKED, PINNED); - - const INNER: &'static usize = Pin::into_inner(PINNED); - assert_eq!(INNER, POINTER); - - const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) }; - assert_eq!(INNER_UNCHECKED, POINTER); - - const REF: &'static usize = PINNED.get_ref(); - assert_eq!(REF, POINTER); - - const INT: u8 = 42; - const STATIC_REF: Pin<&'static u8> = Pin::static_ref(&INT); - assert_eq!(*STATIC_REF, INT); - - // Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context. - // A const fn is used because `&mut` is not (yet) usable in constants. - const fn pin_mut_const() { - let _ = Pin::new(&mut 2).into_ref(); - let _ = Pin::new(&mut 2).get_mut(); - let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() }; - } - - pin_mut_const(); -} - -#[allow(unused)] -mod pin_coerce_unsized { - use core::cell::{Cell, RefCell, UnsafeCell}; - use core::pin::Pin; - use core::ptr::NonNull; - - pub trait MyTrait {} - impl MyTrait for String {} - - // These Pins should continue to compile. - // Do note that these instances of Pin types cannot be used - // meaningfully because all methods require a Deref/DerefMut - // bounds on the pointer type and Cell, RefCell and UnsafeCell - // do not implement Deref/DerefMut. - - pub fn cell(arg: Pin>>) -> Pin>> { - arg - } - pub fn ref_cell(arg: Pin>>) -> Pin>> { - arg - } - pub fn unsafe_cell(arg: Pin>>) -> Pin>> { - arg - } - - // These sensible Pin coercions are possible. - pub fn pin_mut_ref(arg: Pin<&mut String>) -> Pin<&mut dyn MyTrait> { - arg - } - pub fn pin_ref(arg: Pin<&String>) -> Pin<&dyn MyTrait> { - arg - } - pub fn pin_ptr(arg: Pin<*const String>) -> Pin<*const dyn MyTrait> { - arg - } - pub fn pin_ptr_mut(arg: Pin<*mut String>) -> Pin<*mut dyn MyTrait> { - arg - } - pub fn pin_non_null(arg: Pin>) -> Pin> { - arg - } - pub fn nesting_pins(arg: Pin>) -> Pin> { - arg - } -} diff --git a/library/core/tests/pin_macro.rs b/library/core/tests/pin_macro.rs deleted file mode 100644 index 43542397a61..00000000000 --- a/library/core/tests/pin_macro.rs +++ /dev/null @@ -1,32 +0,0 @@ -// edition:2021 - -use core::marker::PhantomPinned; -use core::mem::{drop as stuff, transmute}; -use core::pin::{Pin, pin}; - -#[test] -fn basic() { - let it: Pin<&mut PhantomPinned> = pin!(PhantomPinned); - stuff(it); -} - -#[test] -fn extension_works_through_block() { - let it: Pin<&mut PhantomPinned> = { pin!(PhantomPinned) }; - stuff(it); -} - -#[test] -fn extension_works_through_unsafe_block() { - // "retro-type-inference" works as well. - let it: Pin<&mut PhantomPinned> = unsafe { pin!(transmute(())) }; - stuff(it); -} - -#[test] -fn unsize_coercion() { - let slice: Pin<&mut [PhantomPinned]> = pin!([PhantomPinned; 2]); - stuff(slice); - let dyn_obj: Pin<&mut dyn Send> = pin!([PhantomPinned; 2]); - stuff(dyn_obj); -} diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs deleted file mode 100644 index 7cefb615d03..00000000000 --- a/library/core/tests/ptr.rs +++ /dev/null @@ -1,994 +0,0 @@ -use core::cell::RefCell; -use core::marker::Freeze; -use core::mem::{self, MaybeUninit}; -use core::num::NonZero; -use core::ptr; -use core::ptr::*; -use std::fmt::{Debug, Display}; - -#[test] -fn test_const_from_raw_parts() { - const SLICE: &[u8] = &[1, 2, 3, 4]; - const FROM_RAW: &[u8] = unsafe { &*slice_from_raw_parts(SLICE.as_ptr(), SLICE.len()) }; - assert_eq!(SLICE, FROM_RAW); - - let slice = &[1, 2, 3, 4, 5]; - let from_raw = unsafe { &*slice_from_raw_parts(slice.as_ptr(), 2) }; - assert_eq!(&slice[..2], from_raw); -} - -#[test] -fn test() { - unsafe { - #[repr(C)] - struct Pair { - fst: isize, - snd: isize, - } - let mut p = Pair { fst: 10, snd: 20 }; - let pptr: *mut Pair = addr_of_mut!(p); - let iptr: *mut isize = pptr as *mut isize; - assert_eq!(*iptr, 10); - *iptr = 30; - assert_eq!(*iptr, 30); - assert_eq!(p.fst, 30); - - *pptr = Pair { fst: 50, snd: 60 }; - assert_eq!(*iptr, 50); - assert_eq!(p.fst, 50); - assert_eq!(p.snd, 60); - - let v0 = vec![32000u16, 32001u16, 32002u16]; - let mut v1 = vec![0u16, 0u16, 0u16]; - - copy(v0.as_ptr().offset(1), v1.as_mut_ptr().offset(1), 1); - assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16)); - copy(v0.as_ptr().offset(2), v1.as_mut_ptr(), 1); - assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16)); - copy(v0.as_ptr(), v1.as_mut_ptr().offset(2), 1); - assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16)); - } -} - -#[test] -fn test_is_null() { - let p: *const isize = null(); - assert!(p.is_null()); - - let q = p.wrapping_offset(1); - assert!(!q.is_null()); - - let mp: *mut isize = null_mut(); - assert!(mp.is_null()); - - let mq = mp.wrapping_offset(1); - assert!(!mq.is_null()); - - // Pointers to unsized types -- slices - let s: &mut [u8] = &mut [1, 2, 3]; - let cs: *const [u8] = s; - assert!(!cs.is_null()); - - let ms: *mut [u8] = s; - assert!(!ms.is_null()); - - let cz: *const [u8] = &[]; - assert!(!cz.is_null()); - - let mz: *mut [u8] = &mut []; - assert!(!mz.is_null()); - - let ncs: *const [u8] = null::<[u8; 3]>(); - assert!(ncs.is_null()); - - let nms: *mut [u8] = null_mut::<[u8; 3]>(); - assert!(nms.is_null()); - - // Pointers to unsized types -- trait objects - let ci: *const dyn ToString = &3; - assert!(!ci.is_null()); - - let mi: *mut dyn ToString = &mut 3; - assert!(!mi.is_null()); - - let nci: *const dyn ToString = null::(); - assert!(nci.is_null()); - - let nmi: *mut dyn ToString = null_mut::(); - assert!(nmi.is_null()); - - extern "C" { - type Extern; - } - let ec: *const Extern = null::(); - assert!(ec.is_null()); - - let em: *mut Extern = null_mut::(); - assert!(em.is_null()); -} - -#[test] -fn test_as_ref() { - unsafe { - let p: *const isize = null(); - assert_eq!(p.as_ref(), None); - - let q: *const isize = &2; - assert_eq!(q.as_ref().unwrap(), &2); - - let p: *mut isize = null_mut(); - assert_eq!(p.as_ref(), None); - - let q: *mut isize = &mut 2; - assert_eq!(q.as_ref().unwrap(), &2); - - // Lifetime inference - let u = 2isize; - { - let p = &u as *const isize; - assert_eq!(p.as_ref().unwrap(), &2); - } - - // Pointers to unsized types -- slices - let s: &mut [u8] = &mut [1, 2, 3]; - let cs: *const [u8] = s; - assert_eq!(cs.as_ref(), Some(&*s)); - - let ms: *mut [u8] = s; - assert_eq!(ms.as_ref(), Some(&*s)); - - let cz: *const [u8] = &[]; - assert_eq!(cz.as_ref(), Some(&[][..])); - - let mz: *mut [u8] = &mut []; - assert_eq!(mz.as_ref(), Some(&[][..])); - - let ncs: *const [u8] = null::<[u8; 3]>(); - assert_eq!(ncs.as_ref(), None); - - let nms: *mut [u8] = null_mut::<[u8; 3]>(); - assert_eq!(nms.as_ref(), None); - - // Pointers to unsized types -- trait objects - let ci: *const dyn ToString = &3; - assert!(ci.as_ref().is_some()); - - let mi: *mut dyn ToString = &mut 3; - assert!(mi.as_ref().is_some()); - - let nci: *const dyn ToString = null::(); - assert!(nci.as_ref().is_none()); - - let nmi: *mut dyn ToString = null_mut::(); - assert!(nmi.as_ref().is_none()); - } -} - -#[test] -fn test_as_mut() { - unsafe { - let p: *mut isize = null_mut(); - assert!(p.as_mut() == None); - - let q: *mut isize = &mut 2; - assert!(q.as_mut().unwrap() == &mut 2); - - // Lifetime inference - let mut u = 2isize; - { - let p = &mut u as *mut isize; - assert!(p.as_mut().unwrap() == &mut 2); - } - - // Pointers to unsized types -- slices - let s: &mut [u8] = &mut [1, 2, 3]; - let ms: *mut [u8] = s; - assert_eq!(ms.as_mut(), Some(&mut [1, 2, 3][..])); - - let mz: *mut [u8] = &mut []; - assert_eq!(mz.as_mut(), Some(&mut [][..])); - - let nms: *mut [u8] = null_mut::<[u8; 3]>(); - assert_eq!(nms.as_mut(), None); - - // Pointers to unsized types -- trait objects - let mi: *mut dyn ToString = &mut 3; - assert!(mi.as_mut().is_some()); - - let nmi: *mut dyn ToString = null_mut::(); - assert!(nmi.as_mut().is_none()); - } -} - -#[test] -fn test_ptr_addition() { - unsafe { - let xs = vec![5; 16]; - let mut ptr = xs.as_ptr(); - let end = ptr.offset(16); - - while ptr < end { - assert_eq!(*ptr, 5); - ptr = ptr.offset(1); - } - - let mut xs_mut = xs; - let mut m_ptr = xs_mut.as_mut_ptr(); - let m_end = m_ptr.offset(16); - - while m_ptr < m_end { - *m_ptr += 5; - m_ptr = m_ptr.offset(1); - } - - assert!(xs_mut == vec![10; 16]); - } -} - -#[test] -fn test_ptr_subtraction() { - unsafe { - let xs = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let mut idx = 9; - let ptr = xs.as_ptr(); - - while idx >= 0 { - assert_eq!(*(ptr.offset(idx as isize)), idx as isize); - idx = idx - 1; - } - - let mut xs_mut = xs; - let m_start = xs_mut.as_mut_ptr(); - let mut m_ptr = m_start.offset(9); - - loop { - *m_ptr += *m_ptr; - if m_ptr == m_start { - break; - } - m_ptr = m_ptr.offset(-1); - } - - assert_eq!(xs_mut, [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]); - } -} - -#[test] -fn test_set_memory() { - let mut xs = [0u8; 20]; - let ptr = xs.as_mut_ptr(); - unsafe { - write_bytes(ptr, 5u8, xs.len()); - } - assert!(xs == [5u8; 20]); -} - -#[test] -fn test_set_memory_const() { - const XS: [u8; 20] = { - let mut xs = [0u8; 20]; - let ptr = xs.as_mut_ptr(); - unsafe { - ptr.write_bytes(5u8, xs.len()); - } - xs - }; - - assert!(XS == [5u8; 20]); -} - -#[test] -fn test_unsized_nonnull() { - let xs: &[i32] = &[1, 2, 3]; - let ptr = unsafe { NonNull::new_unchecked(xs as *const [i32] as *mut [i32]) }; - let ys = unsafe { ptr.as_ref() }; - let zs: &[i32] = &[1, 2, 3]; - assert!(ys == zs); -} - -#[test] -fn test_const_nonnull_new() { - const { - assert!(NonNull::new(core::ptr::null_mut::<()>()).is_none()); - - let value = &mut 0u32; - let mut ptr = NonNull::new(value).unwrap(); - unsafe { *ptr.as_mut() = 42 }; - - let reference = unsafe { &*ptr.as_ref() }; - assert!(*reference == *value); - assert!(*reference == 42); - }; -} - -#[test] -#[cfg(unix)] // printf may not be available on other platforms -#[allow(deprecated)] // For SipHasher -#[allow(unpredictable_function_pointer_comparisons)] -pub fn test_variadic_fnptr() { - use core::ffi; - use core::hash::{Hash, SipHasher}; - extern "C" { - // This needs to use the correct function signature even though it isn't called as some - // codegen backends make it UB to declare a function with multiple conflicting signatures - // (like LLVM) while others straight up return an error (like Cranelift). - fn printf(_: *const ffi::c_char, ...) -> ffi::c_int; - } - let p: unsafe extern "C" fn(*const ffi::c_char, ...) -> ffi::c_int = printf; - let q = p.clone(); - assert_eq!(p, q); - assert!(!(p < q)); - let mut s = SipHasher::new(); - assert_eq!(p.hash(&mut s), q.hash(&mut s)); -} - -#[test] -fn write_unaligned_drop() { - thread_local! { - static DROPS: RefCell> = RefCell::new(Vec::new()); - } - - struct Dropper(u32); - - impl Drop for Dropper { - fn drop(&mut self) { - DROPS.with(|d| d.borrow_mut().push(self.0)); - } - } - - { - let c = Dropper(0); - let mut t = Dropper(1); - unsafe { - write_unaligned(&mut t, c); - } - } - DROPS.with(|d| assert_eq!(*d.borrow(), [0])); -} - -#[test] -fn align_offset_zst() { - // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at - // all, because no amount of elements will align the pointer. - let mut p = 1; - while p < 1024 { - assert_eq!(ptr::without_provenance::<()>(p).align_offset(p), 0); - if p != 1 { - assert_eq!(ptr::without_provenance::<()>(p + 1).align_offset(p), !0); - } - p = (p + 1).next_power_of_two(); - } -} - -#[test] -fn align_offset_stride_one() { - // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to - // number of bytes. - let mut align = 1; - while align < 1024 { - for ptr in 1..2 * align { - let expected = ptr % align; - let offset = if expected == 0 { 0 } else { align - expected }; - assert_eq!( - ptr::without_provenance::(ptr).align_offset(align), - offset, - "ptr = {}, align = {}, size = 1", - ptr, - align - ); - } - align = (align + 1).next_power_of_two(); - } -} - -#[test] -fn align_offset_various_strides() { - unsafe fn test_stride(ptr: *const T, align: usize) -> bool { - let numptr = ptr as usize; - let mut expected = usize::MAX; - // Naive but definitely correct way to find the *first* aligned element of stride::. - for el in 0..align { - if (numptr + el * ::std::mem::size_of::()) % align == 0 { - expected = el; - break; - } - } - let got = ptr.align_offset(align); - if got != expected { - eprintln!( - "aligning {:p} (with stride of {}) to {}, expected {}, got {}", - ptr, - ::std::mem::size_of::(), - align, - expected, - got - ); - return true; - } - return false; - } - - // For pointers of stride != 1, we verify the algorithm against the naivest possible - // implementation - let mut align = 1; - let mut x = false; - // Miri is too slow - let limit = if cfg!(miri) { 32 } else { 1024 }; - while align < limit { - for ptr in 1usize..4 * align { - unsafe { - #[repr(packed)] - struct A3(#[allow(dead_code)] u16, #[allow(dead_code)] u8); - x |= test_stride::(ptr::without_provenance::(ptr), align); - - struct A4(#[allow(dead_code)] u32); - x |= test_stride::(ptr::without_provenance::(ptr), align); - - #[repr(packed)] - struct A5(#[allow(dead_code)] u32, #[allow(dead_code)] u8); - x |= test_stride::(ptr::without_provenance::(ptr), align); - - #[repr(packed)] - struct A6(#[allow(dead_code)] u32, #[allow(dead_code)] u16); - x |= test_stride::(ptr::without_provenance::(ptr), align); - - #[repr(packed)] - struct A7(#[allow(dead_code)] u32, #[allow(dead_code)] u16, #[allow(dead_code)] u8); - x |= test_stride::(ptr::without_provenance::(ptr), align); - - #[repr(packed)] - struct A8(#[allow(dead_code)] u32, #[allow(dead_code)] u32); - x |= test_stride::(ptr::without_provenance::(ptr), align); - - #[repr(packed)] - struct A9(#[allow(dead_code)] u32, #[allow(dead_code)] u32, #[allow(dead_code)] u8); - x |= test_stride::(ptr::without_provenance::(ptr), align); - - #[repr(packed)] - struct A10( - #[allow(dead_code)] u32, - #[allow(dead_code)] u32, - #[allow(dead_code)] u16, - ); - x |= test_stride::(ptr::without_provenance::(ptr), align); - - x |= test_stride::(ptr::without_provenance::(ptr), align); - x |= test_stride::(ptr::without_provenance::(ptr), align); - } - } - align = (align + 1).next_power_of_two(); - } - assert!(!x); -} - -#[test] -fn align_offset_issue_103361() { - #[cfg(target_pointer_width = "64")] - const SIZE: usize = 1 << 47; - #[cfg(target_pointer_width = "32")] - const SIZE: usize = 1 << 30; - #[cfg(target_pointer_width = "16")] - const SIZE: usize = 1 << 13; - struct HugeSize(#[allow(dead_code)] [u8; SIZE - 1]); - let _ = ptr::without_provenance::(SIZE).align_offset(SIZE); -} - -#[test] -fn is_aligned() { - let data = 42; - let ptr: *const i32 = &data; - assert!(ptr.is_aligned()); - assert!(ptr.is_aligned_to(1)); - assert!(ptr.is_aligned_to(2)); - assert!(ptr.is_aligned_to(4)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(1)); - assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); - assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); - - // At runtime either `ptr` or `ptr+1` is aligned to 8. - assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); -} - -#[test] -fn offset_from() { - let mut a = [0; 5]; - let ptr1: *mut i32 = &mut a[1]; - let ptr2: *mut i32 = &mut a[3]; - unsafe { - assert_eq!(ptr2.offset_from(ptr1), 2); - assert_eq!(ptr1.offset_from(ptr2), -2); - assert_eq!(ptr1.offset(2), ptr2); - assert_eq!(ptr2.offset(-2), ptr1); - } -} - -#[test] -fn ptr_metadata() { - struct Unit; - struct Pair(A, B); - extern "C" { - type Extern; - } - let () = metadata(&()); - let () = metadata(&Unit); - let () = metadata(&4_u32); - let () = metadata(&String::new()); - let () = metadata(&Some(4_u32)); - let () = metadata(&ptr_metadata); - let () = metadata(&|| {}); - let () = metadata(&[4, 7]); - let () = metadata(&(4, String::new())); - let () = metadata(&Pair(4, String::new())); - let () = metadata(ptr::null::<()>() as *const Extern); - let () = metadata(ptr::null::<()>() as *const <&u32 as std::ops::Deref>::Target); - - assert_eq!(metadata("foo"), 3_usize); - assert_eq!(metadata(&[4, 7][..]), 2_usize); - - let dst_tuple: &(bool, [u8]) = &(true, [0x66, 0x6F, 0x6F]); - let dst_struct: &Pair = &Pair(true, [0x66, 0x6F, 0x6F]); - assert_eq!(metadata(dst_tuple), 3_usize); - assert_eq!(metadata(dst_struct), 3_usize); - unsafe { - let dst_tuple: &(bool, str) = std::mem::transmute(dst_tuple); - let dst_struct: &Pair = std::mem::transmute(dst_struct); - assert_eq!(&dst_tuple.1, "foo"); - assert_eq!(&dst_struct.1, "foo"); - assert_eq!(metadata(dst_tuple), 3_usize); - assert_eq!(metadata(dst_struct), 3_usize); - } - - let vtable_1: DynMetadata = metadata(&4_u16 as &dyn Debug); - let vtable_2: DynMetadata = metadata(&4_u16 as &dyn Display); - let vtable_3: DynMetadata = metadata(&4_u32 as &dyn Display); - let vtable_4: DynMetadata = metadata(&(true, 7_u32) as &(bool, dyn Display)); - let vtable_5: DynMetadata = - metadata(&Pair(true, 7_u32) as &Pair); - unsafe { - let address_1: *const () = std::mem::transmute(vtable_1); - let address_2: *const () = std::mem::transmute(vtable_2); - let address_3: *const () = std::mem::transmute(vtable_3); - let address_4: *const () = std::mem::transmute(vtable_4); - let address_5: *const () = std::mem::transmute(vtable_5); - // Different trait => different vtable pointer - assert_ne!(address_1, address_2); - // Different erased type => different vtable pointer - assert_ne!(address_2, address_3); - // Same erased type and same trait => same vtable pointer. - // This is *not guaranteed*, so we skip it in Miri. - if !cfg!(miri) { - assert_eq!(address_3, address_4); - assert_eq!(address_3, address_5); - } - } -} - -#[test] -fn ptr_metadata_bounds() { - fn metadata_eq_method_address() -> usize { - // The `Metadata` associated type has an `Ord` bound, so this is valid: - <::Metadata as PartialEq>::eq as usize - } - // "Synthetic" trait impls generated by the compiler like those of `Pointee` - // are not checked for bounds of associated type. - // So with a buggy core we could have both: - // * `::Metadata == DynMetadata` - // * `DynMetadata: !PartialEq` - // … and cause an ICE here: - metadata_eq_method_address::(); - - // For this reason, let’s check here that bounds are satisfied: - - let _ = static_assert_expected_bounds_for_metadata::<()>; - let _ = static_assert_expected_bounds_for_metadata::; - let _ = static_assert_expected_bounds_for_metadata::>; - fn _static_assert_associated_type() { - let _ = static_assert_expected_bounds_for_metadata::<::Metadata>; - } - - fn static_assert_expected_bounds_for_metadata() - where - // Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs` - Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin + Freeze, - { - } -} - -#[test] -fn pointee_metadata_debug() { - assert_eq!("()", format!("{:?}", metadata::(&17))); - assert_eq!("2", format!("{:?}", metadata::<[u32]>(&[19, 23]))); - let for_dyn = format!("{:?}", metadata::(&29)); - assert!(for_dyn.starts_with("DynMetadata(0x"), "{:?}", for_dyn); -} - -#[test] -fn dyn_metadata() { - #[derive(Debug)] - #[repr(align(32))] - struct Something(#[allow(dead_code)] [u8; 47]); - - let value = Something([0; 47]); - let trait_object: &dyn Debug = &value; - let meta = metadata(trait_object); - - assert_eq!(meta.size_of(), 64); - assert_eq!(meta.size_of(), std::mem::size_of::()); - assert_eq!(meta.align_of(), 32); - assert_eq!(meta.align_of(), std::mem::align_of::()); - assert_eq!(meta.layout(), std::alloc::Layout::new::()); - - assert!(format!("{meta:?}").starts_with("DynMetadata(0x")); -} - -#[test] -fn from_raw_parts() { - let mut value = 5_u32; - let address = &mut value as *mut _ as *mut (); - let trait_object: &dyn Display = &mut value; - let vtable = metadata(trait_object); - let trait_object = NonNull::from(trait_object); - - assert_eq!(ptr::from_raw_parts(address, vtable), trait_object.as_ptr()); - assert_eq!(ptr::from_raw_parts_mut(address, vtable), trait_object.as_ptr()); - assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), vtable), trait_object); - - let mut array = [5_u32, 5, 5, 5, 5]; - let address = &mut array as *mut _ as *mut (); - let array_ptr = NonNull::from(&mut array); - let slice_ptr = NonNull::from(&mut array[..]); - - assert_eq!(ptr::from_raw_parts(address, ()), array_ptr.as_ptr()); - assert_eq!(ptr::from_raw_parts_mut(address, ()), array_ptr.as_ptr()); - assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), ()), array_ptr); - - assert_eq!(ptr::from_raw_parts(address, 5), slice_ptr.as_ptr()); - assert_eq!(ptr::from_raw_parts_mut(address, 5), slice_ptr.as_ptr()); - assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), 5), slice_ptr); -} - -#[test] -fn thin_box() { - let foo = ThinBox::::new(4); - assert_eq!(foo.to_string(), "4"); - drop(foo); - let bar = ThinBox::::new(7); - assert_eq!(bar.to_string(), "7"); - - // A slightly more interesting library that could be built on top of metadata APIs. - // - // * It could be generalized to any `T: ?Sized` (not just trait object) - // if `{size,align}_of_for_meta(T::Metadata)` are added. - // * Constructing a `ThinBox` without consuming and deallocating a `Box` - // requires either the unstable `Unsize` marker trait, - // or the unstable `unsized_locals` language feature, - // or taking `&dyn T` and restricting to `T: Copy`. - - use std::alloc::*; - use std::marker::PhantomData; - - struct ThinBox - where - T: ?Sized + Pointee>, - { - ptr: NonNull>, - phantom: PhantomData, - } - - impl ThinBox - where - T: ?Sized + Pointee>, - { - pub fn new>(value: Value) -> Self { - let unsized_: &T = &value; - let meta = metadata(unsized_); - let meta_layout = Layout::for_value(&meta); - let value_layout = Layout::for_value(&value); - let (layout, offset) = meta_layout.extend(value_layout).unwrap(); - // `DynMetadata` is pointer-sized: - assert!(layout.size() > 0); - // If `ThinBox` is generalized to any `T: ?Sized`, - // handle ZSTs with a dangling pointer without going through `alloc()`, - // like `Box` does. - unsafe { - let ptr = NonNull::new(alloc(layout)) - .unwrap_or_else(|| handle_alloc_error(layout)) - .cast::>(); - ptr.as_ptr().write(meta); - ptr.as_ptr().byte_add(offset).cast::().write(value); - Self { ptr, phantom: PhantomData } - } - } - - fn meta(&self) -> DynMetadata { - unsafe { *self.ptr.as_ref() } - } - - fn layout(&self) -> (Layout, usize) { - let meta = self.meta(); - Layout::for_value(&meta).extend(meta.layout()).unwrap() - } - - fn value_ptr(&self) -> *const T { - let (_, offset) = self.layout(); - let data_ptr = unsafe { self.ptr.cast::().as_ptr().add(offset) }; - ptr::from_raw_parts(data_ptr, self.meta()) - } - - fn value_mut_ptr(&mut self) -> *mut T { - let (_, offset) = self.layout(); - // FIXME: can this line be shared with the same in `value_ptr()` - // without upsetting Stacked Borrows? - let data_ptr = unsafe { self.ptr.cast::().as_ptr().add(offset) }; - from_raw_parts_mut(data_ptr, self.meta()) - } - } - - impl std::ops::Deref for ThinBox - where - T: ?Sized + Pointee>, - { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.value_ptr() } - } - } - - impl std::ops::DerefMut for ThinBox - where - T: ?Sized + Pointee>, - { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.value_mut_ptr() } - } - } - - impl std::ops::Drop for ThinBox - where - T: ?Sized + Pointee>, - { - fn drop(&mut self) { - let (layout, _) = self.layout(); - unsafe { - drop_in_place::(&mut **self); - dealloc(self.ptr.cast().as_ptr(), layout); - } - } - } -} - -#[test] -fn nonnull_tagged_pointer_with_provenance() { - let raw_pointer = Box::into_raw(Box::new(10)); - - let mut p = TaggedPointer::new(raw_pointer).unwrap(); - assert_eq!(p.tag(), 0); - - p.set_tag(1); - assert_eq!(p.tag(), 1); - assert_eq!(unsafe { *p.pointer().as_ptr() }, 10); - - p.set_tag(3); - assert_eq!(p.tag(), 3); - assert_eq!(unsafe { *p.pointer().as_ptr() }, 10); - - unsafe { drop(Box::from_raw(p.pointer().as_ptr())) }; - - /// A non-null pointer type which carries several bits of metadata and maintains provenance. - #[repr(transparent)] - pub struct TaggedPointer(NonNull); - - impl Clone for TaggedPointer { - fn clone(&self) -> Self { - Self(self.0) - } - } - - impl Copy for TaggedPointer {} - - impl TaggedPointer { - /// The ABI-required minimum alignment of the `P` type. - pub const ALIGNMENT: usize = core::mem::align_of::(); - /// A mask for data-carrying bits of the address. - pub const DATA_MASK: usize = !Self::ADDRESS_MASK; - /// Number of available bits of storage in the address. - pub const NUM_BITS: u32 = Self::ALIGNMENT.trailing_zeros(); - /// A mask for the non-data-carrying bits of the address. - pub const ADDRESS_MASK: usize = usize::MAX << Self::NUM_BITS; - - /// Creates a new tagged pointer from a possibly null pointer. - pub fn new(pointer: *mut T) -> Option> { - Some(TaggedPointer(NonNull::new(pointer)?)) - } - - /// Consume this tagged pointer and produce a raw mutable pointer to the - /// memory location. - pub fn pointer(self) -> NonNull { - // SAFETY: The `addr` guaranteed to have bits set in the Self::ADDRESS_MASK, so the result will be non-null. - self.0 - .map_addr(|addr| unsafe { NonZero::new_unchecked(addr.get() & Self::ADDRESS_MASK) }) - } - - /// Consume this tagged pointer and produce the data it carries. - pub fn tag(&self) -> usize { - self.0.addr().get() & Self::DATA_MASK - } - - /// Update the data this tagged pointer carries to a new value. - pub fn set_tag(&mut self, data: usize) { - assert_eq!( - data & Self::ADDRESS_MASK, - 0, - "cannot set more data beyond the lowest NUM_BITS" - ); - let data = data & Self::DATA_MASK; - - // SAFETY: This value will always be non-zero because the upper bits (from - // ADDRESS_MASK) will always be non-zero. This a property of the type and its - // construction. - self.0 = self.0.map_addr(|addr| unsafe { - NonZero::new_unchecked((addr.get() & Self::ADDRESS_MASK) | data) - }) - } - } -} - -#[test] -fn swap_copy_untyped() { - // We call `{swap,copy}{,_nonoverlapping}` at `bool` type on data that is not a valid bool. - // These should all do untyped copies, so this should work fine. - let mut x = 5u8; - let mut y = 6u8; - - let ptr1 = addr_of_mut!(x).cast::(); - let ptr2 = addr_of_mut!(y).cast::(); - - unsafe { - ptr::swap(ptr1, ptr2); - ptr::swap_nonoverlapping(ptr1, ptr2, 1); - } - assert_eq!(x, 5); - assert_eq!(y, 6); - - unsafe { - ptr::copy(ptr1, ptr2, 1); - ptr::copy_nonoverlapping(ptr1, ptr2, 1); - } - assert_eq!(x, 5); - assert_eq!(y, 5); -} - -#[test] -fn test_const_copy_ptr() { - // `copy` and `copy_nonoverlapping` are thin layers on top of intrinsics. Ensure they correctly - // deal with pointers even when the pointers cross the boundary from one "element" being copied - // to another. - const { - let ptr1 = &1; - let mut ptr2 = &666; - - // Copy ptr1 to ptr2, bytewise. - unsafe { - ptr::copy( - &ptr1 as *const _ as *const MaybeUninit, - &mut ptr2 as *mut _ as *mut MaybeUninit, - mem::size_of::<&i32>(), - ); - } - - // Make sure they still work. - assert!(*ptr1 == 1); - assert!(*ptr2 == 1); - }; - - const { - let ptr1 = &1; - let mut ptr2 = &666; - - // Copy ptr1 to ptr2, bytewise. - unsafe { - ptr::copy_nonoverlapping( - &ptr1 as *const _ as *const MaybeUninit, - &mut ptr2 as *mut _ as *mut MaybeUninit, - mem::size_of::<&i32>(), - ); - } - - // Make sure they still work. - assert!(*ptr1 == 1); - assert!(*ptr2 == 1); - }; -} - -#[test] -fn test_const_swap_ptr() { - // The `swap` functions are implemented in the library, they are not primitives. - // Only `swap_nonoverlapping` takes a count; pointers that cross multiple elements - // are *not* supported. - // We put the pointer at an odd offset in the type and copy them as an array of bytes, - // which should catch most of the ways that the library implementation can get it wrong. - - #[cfg(target_pointer_width = "32")] - type HalfPtr = i16; - #[cfg(target_pointer_width = "64")] - type HalfPtr = i32; - - #[repr(C, packed)] - #[allow(unused)] - struct S { - f1: HalfPtr, - // Crucially this field is at an offset that is not a multiple of the pointer size. - ptr: &'static i32, - // Make sure the entire type does not have a power-of-2 size: - // make it 3 pointers in size. This used to hit a bug in `swap_nonoverlapping`. - f2: [HalfPtr; 3], - } - - // Ensure the entire thing is usize-aligned, so in principle this - // looks like it could be eligible for a `usize` copying loop. - #[cfg_attr(target_pointer_width = "32", repr(align(4)))] - #[cfg_attr(target_pointer_width = "64", repr(align(8)))] - struct A(S); - - const { - let mut s1 = A(S { ptr: &1, f1: 0, f2: [0; 3] }); - let mut s2 = A(S { ptr: &666, f1: 0, f2: [0; 3] }); - - // Swap ptr1 and ptr2, as an array. - type T = [u8; mem::size_of::()]; - unsafe { - ptr::swap(ptr::from_mut(&mut s1).cast::(), ptr::from_mut(&mut s2).cast::()); - } - - // Make sure they still work. - assert!(*s1.0.ptr == 666); - assert!(*s2.0.ptr == 1); - - // Swap them back, again as an array. - unsafe { - ptr::swap_nonoverlapping( - ptr::from_mut(&mut s1).cast::(), - ptr::from_mut(&mut s2).cast::(), - 1, - ); - } - - // Make sure they still work. - assert!(*s1.0.ptr == 1); - assert!(*s2.0.ptr == 666); - }; -} - -#[test] -fn test_null_array_as_slice() { - let arr: *mut [u8; 4] = null_mut(); - let ptr: *mut [u8] = arr.as_mut_slice(); - assert!(ptr.is_null()); - assert_eq!(ptr.len(), 4); - - let arr: *const [u8; 4] = null(); - let ptr: *const [u8] = arr.as_slice(); - assert!(ptr.is_null()); - assert_eq!(ptr.len(), 4); -} - -#[test] -fn test_ptr_from_raw_parts_in_const() { - const EMPTY_SLICE_PTR: *const [i32] = - std::ptr::slice_from_raw_parts(std::ptr::without_provenance(123), 456); - assert_eq!(EMPTY_SLICE_PTR.addr(), 123); - assert_eq!(EMPTY_SLICE_PTR.len(), 456); -} - -#[test] -fn test_ptr_metadata_in_const() { - use std::fmt::Debug; - - const ARRAY_META: () = std::ptr::metadata::<[u16; 3]>(&[1, 2, 3]); - const SLICE_META: usize = std::ptr::metadata::<[u16]>(&[1, 2, 3]); - const DYN_META: DynMetadata = std::ptr::metadata::(&[0_u8; 42]); - assert_eq!(ARRAY_META, ()); - assert_eq!(SLICE_META, 3); - assert_eq!(DYN_META.size_of(), 42); -} diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs deleted file mode 100644 index 90ec844bc57..00000000000 --- a/library/core/tests/result.rs +++ /dev/null @@ -1,423 +0,0 @@ -use core::ops::DerefMut; -use core::option::*; - -fn op1() -> Result { - Ok(666) -} -fn op2() -> Result { - Err("sadface") -} - -#[test] -fn test_and() { - assert_eq!(op1().and(Ok(667)).unwrap(), 667); - assert_eq!(op1().and(Err::("bad")).unwrap_err(), "bad"); - - assert_eq!(op2().and(Ok(667)).unwrap_err(), "sadface"); - assert_eq!(op2().and(Err::("bad")).unwrap_err(), "sadface"); -} - -#[test] -fn test_and_then() { - assert_eq!(op1().and_then(|i| Ok::(i + 1)).unwrap(), 667); - assert_eq!(op1().and_then(|_| Err::("bad")).unwrap_err(), "bad"); - - assert_eq!(op2().and_then(|i| Ok::(i + 1)).unwrap_err(), "sadface"); - assert_eq!(op2().and_then(|_| Err::("bad")).unwrap_err(), "sadface"); -} - -#[test] -fn test_or() { - assert_eq!(op1().or(Ok::<_, &'static str>(667)).unwrap(), 666); - assert_eq!(op1().or(Err("bad")).unwrap(), 666); - - assert_eq!(op2().or(Ok::<_, &'static str>(667)).unwrap(), 667); - assert_eq!(op2().or(Err("bad")).unwrap_err(), "bad"); -} - -#[test] -fn test_or_else() { - assert_eq!(op1().or_else(|_| Ok::(667)).unwrap(), 666); - assert_eq!(op1().or_else(|e| Err::(e)).unwrap(), 666); - - assert_eq!(op2().or_else(|_| Ok::(667)).unwrap(), 667); - assert_eq!(op2().or_else(|e| Err::(e)).unwrap_err(), "sadface"); -} - -#[test] -fn test_impl_map() { - assert!(Ok::(1).map(|x| x + 1) == Ok(2)); - assert!(Err::(1).map(|x| x + 1) == Err(1)); -} - -#[test] -fn test_impl_map_err() { - assert!(Ok::(1).map_err(|x| x + 1) == Ok(1)); - assert!(Err::(1).map_err(|x| x + 1) == Err(2)); -} - -#[test] -fn test_collect() { - let v: Result, ()> = (0..0).map(|_| Ok::(0)).collect(); - assert!(v == Ok(vec![])); - - let v: Result, ()> = (0..3).map(|x| Ok::(x)).collect(); - assert!(v == Ok(vec![0, 1, 2])); - - let v: Result, isize> = (0..3).map(|x| if x > 1 { Err(x) } else { Ok(x) }).collect(); - assert!(v == Err(2)); - - // test that it does not take more elements than it needs - let mut functions: [Box Result<(), isize>>; 3] = - [Box::new(|| Ok(())), Box::new(|| Err(1)), Box::new(|| panic!())]; - - let v: Result, isize> = functions.iter_mut().map(|f| (*f)()).collect(); - assert!(v == Err(1)); -} - -#[test] -fn test_fmt_default() { - let ok: Result = Ok(100); - let err: Result = Err("Err"); - - let s = format!("{ok:?}"); - assert_eq!(s, "Ok(100)"); - let s = format!("{err:?}"); - assert_eq!(s, "Err(\"Err\")"); -} - -#[test] -fn test_unwrap_or() { - let ok: Result = Ok(100); - let ok_err: Result = Err("Err"); - - assert_eq!(ok.unwrap_or(50), 100); - assert_eq!(ok_err.unwrap_or(50), 50); -} - -#[test] -fn test_unwrap_or_else() { - fn handler(msg: &'static str) -> isize { - if msg == "I got this." { 50 } else { panic!("BadBad") } - } - - let ok: Result = Ok(100); - let ok_err: Result = Err("I got this."); - - assert_eq!(ok.unwrap_or_else(handler), 100); - assert_eq!(ok_err.unwrap_or_else(handler), 50); -} - -#[test] -#[should_panic] -pub fn test_unwrap_or_else_panic() { - fn handler(msg: &'static str) -> isize { - if msg == "I got this." { 50 } else { panic!("BadBad") } - } - - let bad_err: Result = Err("Unrecoverable mess."); - let _: isize = bad_err.unwrap_or_else(handler); -} - -#[test] -fn test_unwrap_unchecked() { - let ok: Result = Ok(100); - assert_eq!(unsafe { ok.unwrap_unchecked() }, 100); -} - -#[test] -fn test_unwrap_err_unchecked() { - let ok_err: Result = Err("Err"); - assert_eq!(unsafe { ok_err.unwrap_err_unchecked() }, "Err"); -} - -#[test] -pub fn test_expect_ok() { - let ok: Result = Ok(100); - assert_eq!(ok.expect("Unexpected error"), 100); -} -#[test] -#[should_panic(expected = "Got expected error: \"All good\"")] -pub fn test_expect_err() { - let err: Result = Err("All good"); - err.expect("Got expected error"); -} - -#[test] -pub fn test_expect_err_err() { - let ok: Result<&'static str, isize> = Err(100); - assert_eq!(ok.expect_err("Unexpected ok"), 100); -} -#[test] -#[should_panic(expected = "Got expected ok: \"All good\"")] -pub fn test_expect_err_ok() { - let err: Result<&'static str, isize> = Ok("All good"); - err.expect_err("Got expected ok"); -} - -#[test] -pub fn test_iter() { - let ok: Result = Ok(100); - let mut it = ok.iter(); - assert_eq!(it.size_hint(), (1, Some(1))); - assert_eq!(it.next(), Some(&100)); - assert_eq!(it.size_hint(), (0, Some(0))); - assert!(it.next().is_none()); - assert_eq!((&ok).into_iter().next(), Some(&100)); - - let err: Result = Err("error"); - assert_eq!(err.iter().next(), None); -} - -#[test] -#[allow(for_loops_over_fallibles)] -pub fn test_iter_mut() { - let mut ok: Result = Ok(100); - for loc in ok.iter_mut() { - *loc = 200; - } - assert_eq!(ok, Ok(200)); - for loc in &mut ok { - *loc = 300; - } - assert_eq!(ok, Ok(300)); - - let mut err: Result = Err("error"); - for loc in err.iter_mut() { - *loc = 200; - } - assert_eq!(err, Err("error")); -} - -#[test] -pub fn test_unwrap_or_default() { - assert_eq!(op1().unwrap_or_default(), 666); - assert_eq!(op2().unwrap_or_default(), 0); -} - -#[test] -#[allow(non_local_definitions)] -pub fn test_into_ok() { - fn infallible_op() -> Result { - Ok(666) - } - - assert_eq!(infallible_op().into_ok(), 666); - - enum MyNeverToken {} - impl From for ! { - fn from(never: MyNeverToken) -> ! { - match never {} - } - } - - fn infallible_op2() -> Result { - Ok(667) - } - - assert_eq!(infallible_op2().into_ok(), 667); -} - -#[test] -#[allow(non_local_definitions)] -pub fn test_into_err() { - fn until_error_op() -> Result { - Err(666) - } - - assert_eq!(until_error_op().into_err(), 666); - - enum MyNeverToken {} - impl From for ! { - fn from(never: MyNeverToken) -> ! { - match never {} - } - } - - fn until_error_op2() -> Result { - Err(667) - } - - assert_eq!(until_error_op2().into_err(), 667); -} - -#[test] -fn test_try() { - fn try_result_ok() -> Result { - let result: Result = Ok(1); - let val = result?; - Ok(val) - } - assert_eq!(try_result_ok(), Ok(1)); - - fn try_result_err() -> Result { - let result: Result = Err(1); - let val = result?; - Ok(val) - } - assert_eq!(try_result_err(), Err(1)); -} - -#[test] -fn test_result_as_deref() { - // &Result::Ok(T).as_deref() -> - // Result<&T::Deref::Target, &E>::Ok(&*T) - let ref_ok = &Result::Ok::<&i32, u8>(&42); - let expected_result = Result::Ok::<&i32, &u8>(&42); - assert_eq!(ref_ok.as_deref(), expected_result); - - let ref_ok = &Result::Ok::(String::from("a result")); - let expected_result = Result::Ok::<&str, &u32>("a result"); - assert_eq!(ref_ok.as_deref(), expected_result); - - let ref_ok = &Result::Ok::, u32>(vec![1, 2, 3, 4, 5]); - let expected_result = Result::Ok::<&[i32], &u32>([1, 2, 3, 4, 5].as_slice()); - assert_eq!(ref_ok.as_deref(), expected_result); - - // &Result::Err(T).as_deref() -> - // Result<&T::Deref::Target, &E>::Err(&*E) - let val = 41; - let ref_err = &Result::Err::<&u8, i32>(val); - let expected_result = Result::Err::<&u8, &i32>(&val); - assert_eq!(ref_err.as_deref(), expected_result); - - let s = String::from("an error"); - let ref_err = &Result::Err::<&u32, String>(s.clone()); - let expected_result = Result::Err::<&u32, &String>(&s); - assert_eq!(ref_err.as_deref(), expected_result); - - let v = vec![5, 4, 3, 2, 1]; - let ref_err = &Result::Err::<&u32, Vec>(v.clone()); - let expected_result = Result::Err::<&u32, &Vec>(&v); - assert_eq!(ref_err.as_deref(), expected_result); -} - -#[test] -fn test_result_as_deref_mut() { - // &mut Result::Ok(T).as_deref_mut() -> - // Result<&mut T::DerefMut::Target, &mut E>::Ok(&mut *T) - let mut val = 42; - let mut expected_val = 42; - let mut_ok = &mut Result::Ok::<&mut i32, u8>(&mut val); - let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val); - assert_eq!(mut_ok.as_deref_mut(), expected_result); - - let mut expected_string = String::from("a result"); - let mut_ok = &mut Result::Ok::(expected_string.clone()); - let expected_result = Result::Ok::<&mut str, &mut u32>(expected_string.deref_mut()); - assert_eq!(mut_ok.as_deref_mut(), expected_result); - - let mut expected_vec = vec![1, 2, 3, 4, 5]; - let mut_ok = &mut Result::Ok::, u32>(expected_vec.clone()); - let expected_result = Result::Ok::<&mut [i32], &mut u32>(expected_vec.as_mut_slice()); - assert_eq!(mut_ok.as_deref_mut(), expected_result); - - // &mut Result::Err(T).as_deref_mut() -> - // Result<&mut T, &mut E>::Err(&mut *E) - let mut val = 41; - let mut_err = &mut Result::Err::<&mut u8, i32>(val); - let expected_result = Result::Err::<&mut u8, &mut i32>(&mut val); - assert_eq!(mut_err.as_deref_mut(), expected_result); - - let mut expected_string = String::from("an error"); - let mut_err = &mut Result::Err::<&mut u32, String>(expected_string.clone()); - let expected_result = Result::Err::<&mut u32, &mut String>(&mut expected_string); - assert_eq!(mut_err.as_deref_mut(), expected_result); - - let mut expected_vec = vec![5, 4, 3, 2, 1]; - let mut_err = &mut Result::Err::<&mut u32, Vec>(expected_vec.clone()); - let expected_result = Result::Err::<&mut u32, &mut Vec>(&mut expected_vec); - assert_eq!(mut_err.as_deref_mut(), expected_result); -} - -#[test] -fn result_const() { - // test that the methods of `Result` are usable in a const context - - const RESULT: Result = Ok(32); - - const REF: Result<&usize, &bool> = RESULT.as_ref(); - assert_eq!(REF, Ok(&32)); - - const IS_OK: bool = RESULT.is_ok(); - assert!(IS_OK); - - const IS_ERR: bool = RESULT.is_err(); - assert!(!IS_ERR) -} - -#[test] -const fn result_const_mut() { - let mut result: Result = Ok(32); - - { - let as_mut = result.as_mut(); - match as_mut { - Ok(v) => *v = 42, - Err(_) => unreachable!(), - } - } - - let mut result_err: Result = Err(false); - - { - let as_mut = result_err.as_mut(); - match as_mut { - Ok(_) => unreachable!(), - Err(v) => *v = true, - } - } -} - -#[test] -fn result_opt_conversions() { - #[derive(Copy, Clone, Debug, PartialEq)] - struct BadNumErr; - - fn try_num(x: i32) -> Result { - if x <= 5 { Ok(x + 1) } else { Err(BadNumErr) } - } - - type ResOpt = Result, BadNumErr>; - type OptRes = Option>; - - let mut x: ResOpt = Ok(Some(5)); - let mut y: OptRes = Some(Ok(5)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Ok(None); - y = None; - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Err(BadNumErr); - y = Some(Err(BadNumErr)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - let res: Result, BadNumErr> = (0..10) - .map(|x| { - let y = try_num(x)?; - Ok(if y % 2 == 0 { Some(y - 1) } else { None }) - }) - .filter_map(Result::transpose) - .collect(); - - assert_eq!(res, Err(BadNumErr)) -} - -#[test] -fn result_try_trait_v2_branch() { - use core::num::NonZero; - use core::ops::ControlFlow::*; - use core::ops::Try; - - assert_eq!(Ok::(4).branch(), Continue(4)); - assert_eq!(Err::(4).branch(), Break(Err(4))); - let one = NonZero::new(1).unwrap(); - assert_eq!(Ok::<(), NonZero>(()).branch(), Continue(())); - assert_eq!(Err::<(), NonZero>(one).branch(), Break(Err(one))); - assert_eq!(Ok::, ()>(one).branch(), Continue(one)); - assert_eq!(Err::, ()>(()).branch(), Break(Err(()))); -} diff --git a/library/core/tests/simd.rs b/library/core/tests/simd.rs deleted file mode 100644 index b8b5f26ca3f..00000000000 --- a/library/core/tests/simd.rs +++ /dev/null @@ -1,13 +0,0 @@ -use core::simd::prelude::*; - -#[test] -fn testing() { - let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]); - let y = -x; - - let h = x * f32x4::splat(0.5); - - let r = y.abs(); - assert_eq!(x, r); - assert_eq!(h, f32x4::splat(0.5)); -} diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs deleted file mode 100644 index 510dd4967c9..00000000000 --- a/library/core/tests/slice.rs +++ /dev/null @@ -1,2688 +0,0 @@ -use core::cell::Cell; -use core::cmp::Ordering; -use core::mem::MaybeUninit; -use core::num::NonZero; -use core::ops::{Range, RangeInclusive}; -use core::slice; - -#[test] -fn test_position() { - let b = [1, 2, 3, 5, 5]; - assert_eq!(b.iter().position(|&v| v == 9), None); - assert_eq!(b.iter().position(|&v| v == 5), Some(3)); - assert_eq!(b.iter().position(|&v| v == 3), Some(2)); - assert_eq!(b.iter().position(|&v| v == 0), None); -} - -#[test] -fn test_rposition() { - let b = [1, 2, 3, 5, 5]; - assert_eq!(b.iter().rposition(|&v| v == 9), None); - assert_eq!(b.iter().rposition(|&v| v == 5), Some(4)); - assert_eq!(b.iter().rposition(|&v| v == 3), Some(2)); - assert_eq!(b.iter().rposition(|&v| v == 0), None); -} - -#[test] -fn test_binary_search() { - let b: [i32; 0] = []; - assert_eq!(b.binary_search(&5), Err(0)); - - let b = [4]; - assert_eq!(b.binary_search(&3), Err(0)); - assert_eq!(b.binary_search(&4), Ok(0)); - assert_eq!(b.binary_search(&5), Err(1)); - - let b = [1, 2, 4, 6, 8, 9]; - assert_eq!(b.binary_search(&5), Err(3)); - assert_eq!(b.binary_search(&6), Ok(3)); - assert_eq!(b.binary_search(&7), Err(4)); - assert_eq!(b.binary_search(&8), Ok(4)); - - let b = [1, 2, 4, 5, 6, 8]; - assert_eq!(b.binary_search(&9), Err(6)); - - let b = [1, 2, 4, 6, 7, 8, 9]; - assert_eq!(b.binary_search(&6), Ok(3)); - assert_eq!(b.binary_search(&5), Err(3)); - assert_eq!(b.binary_search(&8), Ok(5)); - - let b = [1, 2, 4, 5, 6, 8, 9]; - assert_eq!(b.binary_search(&7), Err(5)); - assert_eq!(b.binary_search(&0), Err(0)); - - let b = [1, 3, 3, 3, 7]; - assert_eq!(b.binary_search(&0), Err(0)); - assert_eq!(b.binary_search(&1), Ok(0)); - assert_eq!(b.binary_search(&2), Err(1)); - assert!(match b.binary_search(&3) { - Ok(1..=3) => true, - _ => false, - }); - assert!(match b.binary_search(&3) { - Ok(1..=3) => true, - _ => false, - }); - assert_eq!(b.binary_search(&4), Err(4)); - assert_eq!(b.binary_search(&5), Err(4)); - assert_eq!(b.binary_search(&6), Err(4)); - assert_eq!(b.binary_search(&7), Ok(4)); - assert_eq!(b.binary_search(&8), Err(5)); - - let b = [(); usize::MAX]; - assert_eq!(b.binary_search(&()), Ok(usize::MAX - 1)); -} - -#[test] -fn test_binary_search_by_overflow() { - let b = [(); usize::MAX]; - assert_eq!(b.binary_search_by(|_| Ordering::Equal), Ok(usize::MAX - 1)); - assert_eq!(b.binary_search_by(|_| Ordering::Greater), Err(0)); - assert_eq!(b.binary_search_by(|_| Ordering::Less), Err(usize::MAX)); -} - -#[test] -// Test implementation specific behavior when finding equivalent elements. -// It is ok to break this test but when you do a crater run is highly advisable. -fn test_binary_search_implementation_details() { - let b = [1, 1, 2, 2, 3, 3, 3]; - assert_eq!(b.binary_search(&1), Ok(1)); - assert_eq!(b.binary_search(&2), Ok(3)); - assert_eq!(b.binary_search(&3), Ok(6)); - let b = [1, 1, 1, 1, 1, 3, 3, 3, 3]; - assert_eq!(b.binary_search(&1), Ok(4)); - assert_eq!(b.binary_search(&3), Ok(8)); - let b = [1, 1, 1, 1, 3, 3, 3, 3, 3]; - assert_eq!(b.binary_search(&1), Ok(3)); - assert_eq!(b.binary_search(&3), Ok(8)); -} - -#[test] -fn test_partition_point() { - let b: [i32; 0] = []; - assert_eq!(b.partition_point(|&x| x < 5), 0); - - let b = [4]; - assert_eq!(b.partition_point(|&x| x < 3), 0); - assert_eq!(b.partition_point(|&x| x < 4), 0); - assert_eq!(b.partition_point(|&x| x < 5), 1); - - let b = [1, 2, 4, 6, 8, 9]; - assert_eq!(b.partition_point(|&x| x < 5), 3); - assert_eq!(b.partition_point(|&x| x < 6), 3); - assert_eq!(b.partition_point(|&x| x < 7), 4); - assert_eq!(b.partition_point(|&x| x < 8), 4); - - let b = [1, 2, 4, 5, 6, 8]; - assert_eq!(b.partition_point(|&x| x < 9), 6); - - let b = [1, 2, 4, 6, 7, 8, 9]; - assert_eq!(b.partition_point(|&x| x < 6), 3); - assert_eq!(b.partition_point(|&x| x < 5), 3); - assert_eq!(b.partition_point(|&x| x < 8), 5); - - let b = [1, 2, 4, 5, 6, 8, 9]; - assert_eq!(b.partition_point(|&x| x < 7), 5); - assert_eq!(b.partition_point(|&x| x < 0), 0); - - let b = [1, 3, 3, 3, 7]; - assert_eq!(b.partition_point(|&x| x < 0), 0); - assert_eq!(b.partition_point(|&x| x < 1), 0); - assert_eq!(b.partition_point(|&x| x < 2), 1); - assert_eq!(b.partition_point(|&x| x < 3), 1); - assert_eq!(b.partition_point(|&x| x < 4), 4); - assert_eq!(b.partition_point(|&x| x < 5), 4); - assert_eq!(b.partition_point(|&x| x < 6), 4); - assert_eq!(b.partition_point(|&x| x < 7), 4); - assert_eq!(b.partition_point(|&x| x < 8), 5); -} - -#[test] -fn test_iterator_advance_by() { - let v = &[0, 1, 2, 3, 4]; - - for i in 0..=v.len() { - let mut iter = v.iter(); - assert_eq!(iter.advance_by(i), Ok(())); - assert_eq!(iter.as_slice(), &v[i..]); - } - - let mut iter = v.iter(); - assert_eq!(iter.advance_by(v.len() + 1), Err(NonZero::new(1).unwrap())); - assert_eq!(iter.as_slice(), &[]); - - let mut iter = v.iter(); - assert_eq!(iter.advance_by(3), Ok(())); - assert_eq!(iter.as_slice(), &v[3..]); - assert_eq!(iter.advance_by(2), Ok(())); - assert_eq!(iter.as_slice(), &[]); - assert_eq!(iter.advance_by(0), Ok(())); -} - -#[test] -fn test_iterator_advance_back_by() { - let v = &[0, 1, 2, 3, 4]; - - for i in 0..=v.len() { - let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(i), Ok(())); - assert_eq!(iter.as_slice(), &v[..v.len() - i]); - } - - let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZero::new(1).unwrap())); - assert_eq!(iter.as_slice(), &[]); - - let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(3), Ok(())); - assert_eq!(iter.as_slice(), &v[..v.len() - 3]); - assert_eq!(iter.advance_back_by(2), Ok(())); - assert_eq!(iter.as_slice(), &[]); - assert_eq!(iter.advance_back_by(0), Ok(())); -} - -#[test] -fn test_iterator_nth() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().nth(i).unwrap(), &v[i]); - } - assert_eq!(v.iter().nth(v.len()), None); - - let mut iter = v.iter(); - assert_eq!(iter.nth(2).unwrap(), &v[2]); - assert_eq!(iter.nth(1).unwrap(), &v[4]); -} - -#[test] -fn test_iterator_nth_back() { - let v: &[_] = &[0, 1, 2, 3, 4]; - for i in 0..v.len() { - assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - i - 1]); - } - assert_eq!(v.iter().nth_back(v.len()), None); - - let mut iter = v.iter(); - assert_eq!(iter.nth_back(2).unwrap(), &v[2]); - assert_eq!(iter.nth_back(1).unwrap(), &v[0]); -} - -#[test] -fn test_iterator_last() { - let v: &[_] = &[0, 1, 2, 3, 4]; - assert_eq!(v.iter().last().unwrap(), &4); - assert_eq!(v[..1].iter().last().unwrap(), &0); -} - -#[test] -fn test_iterator_count() { - let v: &[_] = &[0, 1, 2, 3, 4]; - assert_eq!(v.iter().count(), 5); - - let mut iter2 = v.iter(); - iter2.next(); - iter2.next(); - assert_eq!(iter2.count(), 3); -} - -#[test] -fn test_chunks_count() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.chunks(3); - assert_eq!(c.count(), 2); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.chunks(2); - assert_eq!(c2.count(), 3); - - let v3: &[i32] = &[]; - let c3 = v3.chunks(2); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_chunks_nth() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.chunks(2); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[4, 5]); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let mut c2 = v2.chunks(3); - assert_eq!(c2.nth(1).unwrap(), &[3, 4]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_chunks_next() { - let v = [0, 1, 2, 3, 4, 5]; - let mut c = v.chunks(2); - assert_eq!(c.next().unwrap(), &[0, 1]); - assert_eq!(c.next().unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[4, 5]); - assert_eq!(c.next(), None); - - let v = [0, 1, 2, 3, 4, 5, 6, 7]; - let mut c = v.chunks(3); - assert_eq!(c.next().unwrap(), &[0, 1, 2]); - assert_eq!(c.next().unwrap(), &[3, 4, 5]); - assert_eq!(c.next().unwrap(), &[6, 7]); - assert_eq!(c.next(), None); -} - -#[test] -fn test_chunks_next_back() { - let v = [0, 1, 2, 3, 4, 5]; - let mut c = v.chunks(2); - assert_eq!(c.next_back().unwrap(), &[4, 5]); - assert_eq!(c.next_back().unwrap(), &[2, 3]); - assert_eq!(c.next_back().unwrap(), &[0, 1]); - assert_eq!(c.next_back(), None); - - let v = [0, 1, 2, 3, 4, 5, 6, 7]; - let mut c = v.chunks(3); - assert_eq!(c.next_back().unwrap(), &[6, 7]); - assert_eq!(c.next_back().unwrap(), &[3, 4, 5]); - assert_eq!(c.next_back().unwrap(), &[0, 1, 2]); - assert_eq!(c.next_back(), None); -} - -#[test] -fn test_chunks_nth_back() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.chunks(2); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - assert_eq!(c.next(), None); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let mut c2 = v2.chunks(3); - assert_eq!(c2.nth_back(1).unwrap(), &[0, 1, 2]); - assert_eq!(c2.next(), None); - assert_eq!(c2.next_back(), None); - - let v3: &[i32] = &[0, 1, 2, 3, 4]; - let mut c3 = v3.chunks(10); - assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]); - assert_eq!(c3.next(), None); - - let v4: &[i32] = &[0, 1, 2]; - let mut c4 = v4.chunks(10); - assert_eq!(c4.nth_back(1_000_000_000usize), None); -} - -#[test] -fn test_chunks_last() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.chunks(2); - assert_eq!(c.last().unwrap()[1], 5); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.chunks(2); - assert_eq!(c2.last().unwrap()[0], 4); -} - -#[test] -fn test_chunks_zip() { - let v1: &[i32] = &[0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let res = v1 - .chunks(2) - .zip(v2.chunks(2)) - .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) - .collect::>(); - assert_eq!(res, vec![14, 22, 14]); -} - -#[test] -fn test_chunks_mut_count() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.chunks_mut(3); - assert_eq!(c.count(), 2); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.chunks_mut(2); - assert_eq!(c2.count(), 3); - - let v3: &mut [i32] = &mut []; - let c3 = v3.chunks_mut(2); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_chunks_mut_nth() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.chunks_mut(2); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[4, 5]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let mut c2 = v2.chunks_mut(3); - assert_eq!(c2.nth(1).unwrap(), &[3, 4]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_chunks_mut_nth_back() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.chunks_mut(2); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let mut c1 = v1.chunks_mut(3); - assert_eq!(c1.nth_back(1).unwrap(), &[0, 1, 2]); - assert_eq!(c1.next(), None); - - let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let mut c3 = v3.chunks_mut(10); - assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]); - assert_eq!(c3.next(), None); - - let v4: &mut [i32] = &mut [0, 1, 2]; - let mut c4 = v4.chunks_mut(10); - assert_eq!(c4.nth_back(1_000_000_000usize), None); -} - -#[test] -fn test_chunks_mut_last() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.chunks_mut(2); - assert_eq!(c.last().unwrap(), &[4, 5]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.chunks_mut(2); - assert_eq!(c2.last().unwrap(), &[4]); -} - -#[test] -fn test_chunks_mut_zip() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - for (a, b) in v1.chunks_mut(2).zip(v2.chunks(2)) { - let sum = b.iter().sum::(); - for v in a { - *v += sum; - } - } - assert_eq!(v1, [13, 14, 19, 20, 14]); -} - -#[test] -fn test_chunks_mut_zip_aliasing() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let mut it = v1.chunks_mut(2).zip(v2.chunks(2)); - let first = it.next().unwrap(); - let _ = it.next().unwrap(); - assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); -} - -#[test] -fn test_chunks_exact_mut_zip_aliasing() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let mut it = v1.chunks_exact_mut(2).zip(v2.chunks(2)); - let first = it.next().unwrap(); - let _ = it.next().unwrap(); - assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); -} - -#[test] -fn test_rchunks_mut_zip_aliasing() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let mut it = v1.rchunks_mut(2).zip(v2.chunks(2)); - let first = it.next().unwrap(); - let _ = it.next().unwrap(); - assert_eq!(first, (&mut [3, 4][..], &[6, 7][..])); -} - -#[test] -fn test_rchunks_exact_mut_zip_aliasing() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let mut it = v1.rchunks_exact_mut(2).zip(v2.chunks(2)); - let first = it.next().unwrap(); - let _ = it.next().unwrap(); - assert_eq!(first, (&mut [3, 4][..], &[6, 7][..])); -} - -#[test] -fn test_chunks_exact_count() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.chunks_exact(3); - assert_eq!(c.count(), 2); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.chunks_exact(2); - assert_eq!(c2.count(), 2); - - let v3: &[i32] = &[]; - let c3 = v3.chunks_exact(2); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_chunks_exact_nth() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.chunks_exact(2); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[4, 5]); - - let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; - let mut c2 = v2.chunks_exact(3); - assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_chunks_exact_nth_back() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.chunks_exact(2); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - assert_eq!(c.next(), None); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let mut c2 = v2.chunks_exact(3); - assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); - assert_eq!(c2.next(), None); - assert_eq!(c2.next_back(), None); - - let v3: &[i32] = &[0, 1, 2, 3, 4]; - let mut c3 = v3.chunks_exact(10); - assert_eq!(c3.nth_back(0), None); -} - -#[test] -fn test_chunks_exact_last() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.chunks_exact(2); - assert_eq!(c.last().unwrap(), &[4, 5]); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.chunks_exact(2); - assert_eq!(c2.last().unwrap(), &[2, 3]); -} - -#[test] -fn test_chunks_exact_remainder() { - let v: &[i32] = &[0, 1, 2, 3, 4]; - let c = v.chunks_exact(2); - assert_eq!(c.remainder(), &[4]); -} - -#[test] -fn test_chunks_exact_zip() { - let v1: &[i32] = &[0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let res = v1 - .chunks_exact(2) - .zip(v2.chunks_exact(2)) - .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) - .collect::>(); - assert_eq!(res, vec![14, 22]); -} - -#[test] -fn test_chunks_exact_mut_count() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.chunks_exact_mut(3); - assert_eq!(c.count(), 2); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.chunks_exact_mut(2); - assert_eq!(c2.count(), 2); - - let v3: &mut [i32] = &mut []; - let c3 = v3.chunks_exact_mut(2); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_chunks_exact_mut_nth() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.chunks_exact_mut(2); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[4, 5]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; - let mut c2 = v2.chunks_exact_mut(3); - assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_chunks_exact_mut_nth_back() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.chunks_exact_mut(2); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - assert_eq!(c.next(), None); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let mut c2 = v2.chunks_exact_mut(3); - assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); - assert_eq!(c2.next(), None); - assert_eq!(c2.next_back(), None); - - let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let mut c3 = v3.chunks_exact_mut(10); - assert_eq!(c3.nth_back(0), None); -} - -#[test] -fn test_chunks_exact_mut_last() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.chunks_exact_mut(2); - assert_eq!(c.last().unwrap(), &[4, 5]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.chunks_exact_mut(2); - assert_eq!(c2.last().unwrap(), &[2, 3]); -} - -#[test] -fn test_chunks_exact_mut_remainder() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c = v.chunks_exact_mut(2); - assert_eq!(c.into_remainder(), &[4]); -} - -#[test] -fn test_chunks_exact_mut_zip() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - for (a, b) in v1.chunks_exact_mut(2).zip(v2.chunks_exact(2)) { - let sum = b.iter().sum::(); - for v in a { - *v += sum; - } - } - assert_eq!(v1, [13, 14, 19, 20, 4]); -} - -#[test] -fn test_array_chunks_infer() { - let v: &[i32] = &[0, 1, 2, 3, 4, -4]; - let c = v.array_chunks(); - for &[a, b, c] in c { - assert_eq!(a + b + c, 3); - } - - let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; - let total = v2.array_chunks().map(|&[a, b]| a * b).sum::(); - assert_eq!(total, 2 * 3 + 4 * 5); -} - -#[test] -fn test_array_chunks_count() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.array_chunks::<3>(); - assert_eq!(c.count(), 2); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.array_chunks::<2>(); - assert_eq!(c2.count(), 2); - - let v3: &[i32] = &[]; - let c3 = v3.array_chunks::<2>(); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_array_chunks_nth() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.array_chunks::<2>(); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[4, 5]); - - let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; - let mut c2 = v2.array_chunks::<3>(); - assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_array_chunks_nth_back() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.array_chunks::<2>(); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - assert_eq!(c.next(), None); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let mut c2 = v2.array_chunks::<3>(); - assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); - assert_eq!(c2.next(), None); - assert_eq!(c2.next_back(), None); - - let v3: &[i32] = &[0, 1, 2, 3, 4]; - let mut c3 = v3.array_chunks::<10>(); - assert_eq!(c3.nth_back(0), None); -} - -#[test] -fn test_array_chunks_last() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.array_chunks::<2>(); - assert_eq!(c.last().unwrap(), &[4, 5]); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.array_chunks::<2>(); - assert_eq!(c2.last().unwrap(), &[2, 3]); -} - -#[test] -fn test_array_chunks_remainder() { - let v: &[i32] = &[0, 1, 2, 3, 4]; - let c = v.array_chunks::<2>(); - assert_eq!(c.remainder(), &[4]); -} - -#[test] -fn test_array_chunks_zip() { - let v1: &[i32] = &[0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let res = v1 - .array_chunks::<2>() - .zip(v2.array_chunks::<2>()) - .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) - .collect::>(); - assert_eq!(res, vec![14, 22]); -} - -#[test] -fn test_array_chunks_mut_infer() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; - for a in v.array_chunks_mut() { - let sum = a.iter().sum::(); - *a = [sum; 3]; - } - assert_eq!(v, &[3, 3, 3, 12, 12, 12, 6]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; - v2.array_chunks_mut().for_each(|[a, b]| core::mem::swap(a, b)); - assert_eq!(v2, &[1, 0, 3, 2, 5, 4, 6]); -} - -#[test] -fn test_array_chunks_mut_count() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.array_chunks_mut::<3>(); - assert_eq!(c.count(), 2); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.array_chunks_mut::<2>(); - assert_eq!(c2.count(), 2); - - let v3: &mut [i32] = &mut []; - let c3 = v3.array_chunks_mut::<2>(); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_array_chunks_mut_nth() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.array_chunks_mut::<2>(); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[4, 5]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; - let mut c2 = v2.array_chunks_mut::<3>(); - assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_array_chunks_mut_nth_back() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.array_chunks_mut::<2>(); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - assert_eq!(c.next(), None); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let mut c2 = v2.array_chunks_mut::<3>(); - assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); - assert_eq!(c2.next(), None); - assert_eq!(c2.next_back(), None); - - let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let mut c3 = v3.array_chunks_mut::<10>(); - assert_eq!(c3.nth_back(0), None); -} - -#[test] -fn test_array_chunks_mut_last() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.array_chunks_mut::<2>(); - assert_eq!(c.last().unwrap(), &[4, 5]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.array_chunks_mut::<2>(); - assert_eq!(c2.last().unwrap(), &[2, 3]); -} - -#[test] -fn test_array_chunks_mut_remainder() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c = v.array_chunks_mut::<2>(); - assert_eq!(c.into_remainder(), &[4]); -} - -#[test] -fn test_array_chunks_mut_zip() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - for (a, b) in v1.array_chunks_mut::<2>().zip(v2.array_chunks::<2>()) { - let sum = b.iter().sum::(); - for v in a { - *v += sum; - } - } - assert_eq!(v1, [13, 14, 19, 20, 4]); -} - -#[test] -fn test_array_windows_infer() { - let v: &[i32] = &[0, 1, 0, 1]; - assert_eq!(v.array_windows::<2>().count(), 3); - let c = v.array_windows(); - for &[a, b] in c { - assert_eq!(a + b, 1); - } - - let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; - let total = v2.array_windows().map(|&[a, b, c]| a + b + c).sum::(); - assert_eq!(total, 3 + 6 + 9 + 12 + 15); -} - -#[test] -fn test_array_windows_count() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.array_windows::<3>(); - assert_eq!(c.count(), 4); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.array_windows::<6>(); - assert_eq!(c2.count(), 0); - - let v3: &[i32] = &[]; - let c3 = v3.array_windows::<2>(); - assert_eq!(c3.count(), 0); - - let v4: &[()] = &[(); usize::MAX]; - let c4 = v4.array_windows::<1>(); - assert_eq!(c4.count(), usize::MAX); -} - -#[test] -fn test_array_windows_nth() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let snd = v.array_windows::<4>().nth(1); - assert_eq!(snd, Some(&[1, 2, 3, 4])); - let mut arr_windows = v.array_windows::<2>(); - assert_ne!(arr_windows.nth(0), arr_windows.nth(0)); - let last = v.array_windows::<3>().last(); - assert_eq!(last, Some(&[3, 4, 5])); -} - -#[test] -fn test_array_windows_nth_back() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let snd = v.array_windows::<4>().nth_back(1); - assert_eq!(snd, Some(&[1, 2, 3, 4])); - let mut arr_windows = v.array_windows::<2>(); - assert_ne!(arr_windows.nth_back(0), arr_windows.nth_back(0)); -} - -#[test] -fn test_rchunks_count() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.rchunks(3); - assert_eq!(c.count(), 2); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.rchunks(2); - assert_eq!(c2.count(), 3); - - let v3: &[i32] = &[]; - let c3 = v3.rchunks(2); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_rchunks_nth() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks(2); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let mut c2 = v2.rchunks(3); - assert_eq!(c2.nth(1).unwrap(), &[0, 1]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_rchunks_nth_back() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks(2); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next_back().unwrap(), &[4, 5]); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let mut c2 = v2.rchunks(3); - assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]); - assert_eq!(c2.next_back(), None); -} - -#[test] -fn test_rchunks_next() { - let v = [0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks(2); - assert_eq!(c.next().unwrap(), &[4, 5]); - assert_eq!(c.next().unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - assert_eq!(c.next(), None); - - let v = [0, 1, 2, 3, 4, 5, 6, 7]; - let mut c = v.rchunks(3); - assert_eq!(c.next().unwrap(), &[5, 6, 7]); - assert_eq!(c.next().unwrap(), &[2, 3, 4]); - assert_eq!(c.next().unwrap(), &[0, 1]); - assert_eq!(c.next(), None); -} - -#[test] -fn test_rchunks_next_back() { - let v = [0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks(2); - assert_eq!(c.next_back().unwrap(), &[0, 1]); - assert_eq!(c.next_back().unwrap(), &[2, 3]); - assert_eq!(c.next_back().unwrap(), &[4, 5]); - assert_eq!(c.next_back(), None); - - let v = [0, 1, 2, 3, 4, 5, 6, 7]; - let mut c = v.rchunks(3); - assert_eq!(c.next_back().unwrap(), &[0, 1]); - assert_eq!(c.next_back().unwrap(), &[2, 3, 4]); - assert_eq!(c.next_back().unwrap(), &[5, 6, 7]); - assert_eq!(c.next_back(), None); -} - -#[test] -fn test_rchunks_last() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.rchunks(2); - assert_eq!(c.last().unwrap()[1], 1); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.rchunks(2); - assert_eq!(c2.last().unwrap()[0], 0); -} - -#[test] -fn test_rchunks_zip() { - let v1: &[i32] = &[0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let res = v1 - .rchunks(2) - .zip(v2.rchunks(2)) - .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) - .collect::>(); - assert_eq!(res, vec![26, 18, 6]); -} - -#[test] -fn test_rchunks_mut_count() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.rchunks_mut(3); - assert_eq!(c.count(), 2); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.rchunks_mut(2); - assert_eq!(c2.count(), 3); - - let v3: &mut [i32] = &mut []; - let c3 = v3.rchunks_mut(2); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_rchunks_mut_nth() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks_mut(2); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let mut c2 = v2.rchunks_mut(3); - assert_eq!(c2.nth(1).unwrap(), &[0, 1]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_rchunks_mut_nth_back() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks_mut(2); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next_back().unwrap(), &[4, 5]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let mut c2 = v2.rchunks_mut(3); - assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]); - assert_eq!(c2.next_back(), None); -} - -#[test] -fn test_rchunks_mut_next() { - let mut v = [0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks_mut(2); - assert_eq!(c.next().unwrap(), &mut [4, 5]); - assert_eq!(c.next().unwrap(), &mut [2, 3]); - assert_eq!(c.next().unwrap(), &mut [0, 1]); - assert_eq!(c.next(), None); - - let mut v = [0, 1, 2, 3, 4, 5, 6, 7]; - let mut c = v.rchunks_mut(3); - assert_eq!(c.next().unwrap(), &mut [5, 6, 7]); - assert_eq!(c.next().unwrap(), &mut [2, 3, 4]); - assert_eq!(c.next().unwrap(), &mut [0, 1]); - assert_eq!(c.next(), None); -} - -#[test] -fn test_rchunks_mut_next_back() { - let mut v = [0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks_mut(2); - assert_eq!(c.next_back().unwrap(), &mut [0, 1]); - assert_eq!(c.next_back().unwrap(), &mut [2, 3]); - assert_eq!(c.next_back().unwrap(), &mut [4, 5]); - assert_eq!(c.next_back(), None); - - let mut v = [0, 1, 2, 3, 4, 5, 6, 7]; - let mut c = v.rchunks_mut(3); - assert_eq!(c.next_back().unwrap(), &mut [0, 1]); - assert_eq!(c.next_back().unwrap(), &mut [2, 3, 4]); - assert_eq!(c.next_back().unwrap(), &mut [5, 6, 7]); - assert_eq!(c.next_back(), None); -} - -#[test] -fn test_rchunks_mut_last() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.rchunks_mut(2); - assert_eq!(c.last().unwrap(), &[0, 1]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.rchunks_mut(2); - assert_eq!(c2.last().unwrap(), &[0]); -} - -#[test] -fn test_rchunks_mut_zip() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - for (a, b) in v1.rchunks_mut(2).zip(v2.rchunks(2)) { - let sum = b.iter().sum::(); - for v in a { - *v += sum; - } - } - assert_eq!(v1, [6, 16, 17, 22, 23]); -} - -#[test] -fn test_rchunks_exact_count() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.rchunks_exact(3); - assert_eq!(c.count(), 2); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.rchunks_exact(2); - assert_eq!(c2.count(), 2); - - let v3: &[i32] = &[]; - let c3 = v3.rchunks_exact(2); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_rchunks_exact_nth() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks_exact(2); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - - let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; - let mut c2 = v2.rchunks_exact(3); - assert_eq!(c2.nth(1).unwrap(), &[1, 2, 3]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_rchunks_exact_nth_back() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks_exact(2); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next_back().unwrap(), &[4, 5]); - - let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; - let mut c2 = v2.rchunks_exact(3); - assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_rchunks_exact_last() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.rchunks_exact(2); - assert_eq!(c.last().unwrap(), &[0, 1]); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.rchunks_exact(2); - assert_eq!(c2.last().unwrap(), &[1, 2]); -} - -#[test] -fn test_rchunks_exact_remainder() { - let v: &[i32] = &[0, 1, 2, 3, 4]; - let c = v.rchunks_exact(2); - assert_eq!(c.remainder(), &[0]); -} - -#[test] -fn test_rchunks_exact_zip() { - let v1: &[i32] = &[0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let res = v1 - .rchunks_exact(2) - .zip(v2.rchunks_exact(2)) - .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) - .collect::>(); - assert_eq!(res, vec![26, 18]); -} - -#[test] -fn test_rchunks_exact_mut_count() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.rchunks_exact_mut(3); - assert_eq!(c.count(), 2); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.rchunks_exact_mut(2); - assert_eq!(c2.count(), 2); - - let v3: &mut [i32] = &mut []; - let c3 = v3.rchunks_exact_mut(2); - assert_eq!(c3.count(), 0); -} - -#[test] -fn test_rchunks_exact_mut_nth() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks_exact_mut(2); - assert_eq!(c.nth(1).unwrap(), &[2, 3]); - assert_eq!(c.next().unwrap(), &[0, 1]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; - let mut c2 = v2.rchunks_exact_mut(3); - assert_eq!(c2.nth(1).unwrap(), &[1, 2, 3]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_rchunks_exact_mut_nth_back() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let mut c = v.rchunks_exact_mut(2); - assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); - assert_eq!(c.next_back().unwrap(), &[4, 5]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; - let mut c2 = v2.rchunks_exact_mut(3); - assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_rchunks_exact_mut_last() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - let c = v.rchunks_exact_mut(2); - assert_eq!(c.last().unwrap(), &[0, 1]); - - let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c2 = v2.rchunks_exact_mut(2); - assert_eq!(c2.last().unwrap(), &[1, 2]); -} - -#[test] -fn test_rchunks_exact_mut_remainder() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let c = v.rchunks_exact_mut(2); - assert_eq!(c.into_remainder(), &[0]); -} - -#[test] -fn test_rchunks_exact_mut_zip() { - let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - for (a, b) in v1.rchunks_exact_mut(2).zip(v2.rchunks_exact(2)) { - let sum = b.iter().sum::(); - for v in a { - *v += sum; - } - } - assert_eq!(v1, [0, 16, 17, 22, 23]); -} - -#[test] -fn chunks_mut_are_send_and_sync() { - use std::cell::Cell; - use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut}; - use std::sync::MutexGuard; - - fn assert_send_and_sync() - where - ChunksMut<'static, Cell>: Send, - ChunksMut<'static, MutexGuard<'static, u32>>: Sync, - ChunksExactMut<'static, Cell>: Send, - ChunksExactMut<'static, MutexGuard<'static, u32>>: Sync, - RChunksMut<'static, Cell>: Send, - RChunksMut<'static, MutexGuard<'static, u32>>: Sync, - RChunksExactMut<'static, Cell>: Send, - RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync, - { - } - - assert_send_and_sync(); -} - -#[test] -fn test_windows_count() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.windows(3); - assert_eq!(c.count(), 4); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.windows(6); - assert_eq!(c2.count(), 0); - - let v3: &[i32] = &[]; - let c3 = v3.windows(2); - assert_eq!(c3.count(), 0); - - let v4 = &[(); usize::MAX]; - let c4 = v4.windows(1); - assert_eq!(c4.count(), usize::MAX); -} - -#[test] -fn test_windows_nth() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.windows(2); - assert_eq!(c.nth(2).unwrap()[1], 3); - assert_eq!(c.next().unwrap()[0], 3); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let mut c2 = v2.windows(4); - assert_eq!(c2.nth(1).unwrap()[1], 2); - assert_eq!(c2.next(), None); -} - -#[test] -fn test_windows_nth_back() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let mut c = v.windows(2); - assert_eq!(c.nth_back(2).unwrap()[0], 2); - assert_eq!(c.next_back().unwrap()[1], 2); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let mut c2 = v2.windows(4); - assert_eq!(c2.nth_back(1).unwrap()[1], 1); - assert_eq!(c2.next_back(), None); -} - -#[test] -fn test_windows_last() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - let c = v.windows(2); - assert_eq!(c.last().unwrap()[1], 5); - - let v2: &[i32] = &[0, 1, 2, 3, 4]; - let c2 = v2.windows(2); - assert_eq!(c2.last().unwrap()[0], 3); -} - -#[test] -fn test_windows_zip() { - let v1: &[i32] = &[0, 1, 2, 3, 4]; - let v2: &[i32] = &[6, 7, 8, 9, 10]; - - let res = v1 - .windows(2) - .zip(v2.windows(2)) - .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) - .collect::>(); - - assert_eq!(res, [14, 18, 22, 26]); -} - -#[test] -fn test_iter_ref_consistency() { - use std::fmt::Debug; - - fn test(x: T) { - let v: &[T] = &[x, x, x]; - let v_ptrs: [*const T; 3] = match v { - [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], - _ => unreachable!(), - }; - let len = v.len(); - - // nth(i) - for i in 0..len { - assert_eq!(&v[i] as *const _, v_ptrs[i]); // check the v_ptrs array, just to be sure - let nth = v.iter().nth(i).unwrap(); - assert_eq!(nth as *const _, v_ptrs[i]); - } - assert_eq!(v.iter().nth(len), None, "nth(len) should return None"); - - // stepping through with nth(0) - { - let mut it = v.iter(); - for i in 0..len { - let next = it.nth(0).unwrap(); - assert_eq!(next as *const _, v_ptrs[i]); - } - assert_eq!(it.nth(0), None); - } - - // next() - { - let mut it = v.iter(); - for i in 0..len { - let remaining = len - i; - assert_eq!(it.size_hint(), (remaining, Some(remaining))); - - let next = it.next().unwrap(); - assert_eq!(next as *const _, v_ptrs[i]); - } - assert_eq!(it.size_hint(), (0, Some(0))); - assert_eq!(it.next(), None, "The final call to next() should return None"); - } - - // next_back() - { - let mut it = v.iter(); - for i in 0..len { - let remaining = len - i; - assert_eq!(it.size_hint(), (remaining, Some(remaining))); - - let prev = it.next_back().unwrap(); - assert_eq!(prev as *const _, v_ptrs[remaining - 1]); - } - assert_eq!(it.size_hint(), (0, Some(0))); - assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); - } - } - - fn test_mut(x: T) { - let v: &mut [T] = &mut [x, x, x]; - let v_ptrs: [*mut T; 3] = match v { - [ref v1, ref v2, ref v3] => { - [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _] - } - _ => unreachable!(), - }; - let len = v.len(); - - // nth(i) - for i in 0..len { - assert_eq!(&mut v[i] as *mut _, v_ptrs[i]); // check the v_ptrs array, just to be sure - let nth = v.iter_mut().nth(i).unwrap(); - assert_eq!(nth as *mut _, v_ptrs[i]); - } - assert_eq!(v.iter().nth(len), None, "nth(len) should return None"); - - // stepping through with nth(0) - { - let mut it = v.iter(); - for i in 0..len { - let next = it.nth(0).unwrap(); - assert_eq!(next as *const _, v_ptrs[i]); - } - assert_eq!(it.nth(0), None); - } - - // next() - { - let mut it = v.iter_mut(); - for i in 0..len { - let remaining = len - i; - assert_eq!(it.size_hint(), (remaining, Some(remaining))); - - let next = it.next().unwrap(); - assert_eq!(next as *mut _, v_ptrs[i]); - } - assert_eq!(it.size_hint(), (0, Some(0))); - assert_eq!(it.next(), None, "The final call to next() should return None"); - } - - // next_back() - { - let mut it = v.iter_mut(); - for i in 0..len { - let remaining = len - i; - assert_eq!(it.size_hint(), (remaining, Some(remaining))); - - let prev = it.next_back().unwrap(); - assert_eq!(prev as *mut _, v_ptrs[remaining - 1]); - } - assert_eq!(it.size_hint(), (0, Some(0))); - assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); - } - } - - // Make sure iterators and slice patterns yield consistent addresses for various types, - // including ZSTs. - test(0u32); - test(()); - test([0u32; 0]); // ZST with alignment > 0 - test_mut(0u32); - test_mut(()); - test_mut([0u32; 0]); // ZST with alignment > 0 -} - -// The current implementation of SliceIndex fails to handle methods -// orthogonally from range types; therefore, it is worth testing -// all of the indexing operations on each input. -mod slice_index { - // This checks all six indexing methods, given an input range that - // should succeed. (it is NOT suitable for testing invalid inputs) - macro_rules! assert_range_eq { - ($arr:expr, $range:expr, $expected:expr) => { - let mut arr = $arr; - let mut expected = $expected; - { - let s: &[_] = &arr; - let expected: &[_] = &expected; - - assert_eq!(&s[$range], expected, "(in assertion for: index)"); - assert_eq!(s.get($range), Some(expected), "(in assertion for: get)"); - unsafe { - assert_eq!( - s.get_unchecked($range), - expected, - "(in assertion for: get_unchecked)", - ); - } - } - { - let s: &mut [_] = &mut arr; - let expected: &mut [_] = &mut expected; - - assert_eq!(&mut s[$range], expected, "(in assertion for: index_mut)",); - assert_eq!( - s.get_mut($range), - Some(&mut expected[..]), - "(in assertion for: get_mut)", - ); - unsafe { - assert_eq!( - s.get_unchecked_mut($range), - expected, - "(in assertion for: get_unchecked_mut)", - ); - } - } - }; - } - - // Make sure the macro can actually detect bugs, - // because if it can't, then what are we even doing here? - // - // (Be aware this only demonstrates the ability to detect bugs - // in the FIRST method that panics, as the macro is not designed - // to be used in `should_panic`) - #[test] - #[should_panic(expected = "out of range")] - fn assert_range_eq_can_fail_by_panic() { - assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]); - } - - // (Be aware this only demonstrates the ability to detect bugs - // in the FIRST method it calls, as the macro is not designed - // to be used in `should_panic`) - #[test] - #[should_panic(expected = "==")] - fn assert_range_eq_can_fail_by_inequality() { - assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]); - } - - // Test cases for bad index operations. - // - // This generates `should_panic` test cases for Index/IndexMut - // and `None` test cases for get/get_mut. - macro_rules! panic_cases { - ($( - // each test case needs a unique name to namespace the tests - in mod $case_name:ident { - data: $data:expr; - - // optional: - // - // one or more similar inputs for which data[input] succeeds, - // and the corresponding output as an array. This helps validate - // "critical points" where an input range straddles the boundary - // between valid and invalid. - // (such as the input `len..len`, which is just barely valid) - $( - good: data[$good:expr] == $output:expr; - )* - - bad: data[$bad:expr]; - message: $expect_msg:expr; - } - )*) => {$( - mod $case_name { - #[allow(unused_imports)] - use core::ops::Bound; - - #[test] - fn pass() { - let mut v = $data; - - $( assert_range_eq!($data, $good, $output); )* - - { - let v: &[_] = &v; - assert_eq!(v.get($bad), None, "(in None assertion for get)"); - } - - { - let v: &mut [_] = &mut v; - assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)"); - } - } - - #[test] - #[should_panic(expected = $expect_msg)] - fn index_fail() { - let v = $data; - let v: &[_] = &v; - let _v = &v[$bad]; - } - - #[test] - #[should_panic(expected = $expect_msg)] - fn index_mut_fail() { - let mut v = $data; - let v: &mut [_] = &mut v; - let _v = &mut v[$bad]; - } - } - )*}; - } - - #[test] - fn simple() { - let v = [0, 1, 2, 3, 4, 5]; - - assert_range_eq!(v, .., [0, 1, 2, 3, 4, 5]); - assert_range_eq!(v, ..2, [0, 1]); - assert_range_eq!(v, ..=1, [0, 1]); - assert_range_eq!(v, 2.., [2, 3, 4, 5]); - assert_range_eq!(v, 1..4, [1, 2, 3]); - assert_range_eq!(v, 1..=3, [1, 2, 3]); - } - - panic_cases! { - in mod rangefrom_len { - data: [0, 1, 2, 3, 4, 5]; - - good: data[6..] == []; - bad: data[7..]; - message: "out of range"; - } - - in mod rangeto_len { - data: [0, 1, 2, 3, 4, 5]; - - good: data[..6] == [0, 1, 2, 3, 4, 5]; - bad: data[..7]; - message: "out of range"; - } - - in mod rangetoinclusive_len { - data: [0, 1, 2, 3, 4, 5]; - - good: data[..=5] == [0, 1, 2, 3, 4, 5]; - bad: data[..=6]; - message: "out of range"; - } - - in mod rangeinclusive_len { - data: [0, 1, 2, 3, 4, 5]; - - good: data[0..=5] == [0, 1, 2, 3, 4, 5]; - bad: data[0..=6]; - message: "out of range"; - } - - in mod range_len_len { - data: [0, 1, 2, 3, 4, 5]; - - good: data[6..6] == []; - bad: data[7..7]; - message: "out of range"; - } - - in mod rangeinclusive_len_len { - data: [0, 1, 2, 3, 4, 5]; - - good: data[6..=5] == []; - bad: data[7..=6]; - message: "out of range"; - } - - in mod boundpair_len { - data: [0, 1, 2, 3, 4, 5]; - - good: data[(Bound::Included(6), Bound::Unbounded)] == []; - good: data[(Bound::Unbounded, Bound::Included(5))] == [0, 1, 2, 3, 4, 5]; - good: data[(Bound::Unbounded, Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5]; - good: data[(Bound::Included(0), Bound::Included(5))] == [0, 1, 2, 3, 4, 5]; - good: data[(Bound::Included(0), Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5]; - good: data[(Bound::Included(2), Bound::Excluded(4))] == [2, 3]; - good: data[(Bound::Excluded(1), Bound::Included(4))] == [2, 3, 4]; - good: data[(Bound::Excluded(5), Bound::Excluded(6))] == []; - good: data[(Bound::Included(6), Bound::Excluded(6))] == []; - good: data[(Bound::Excluded(5), Bound::Included(5))] == []; - good: data[(Bound::Included(6), Bound::Included(5))] == []; - bad: data[(Bound::Unbounded, Bound::Included(6))]; - message: "out of range"; - } - } - - panic_cases! { - in mod rangeinclusive_exhausted { - data: [0, 1, 2, 3, 4, 5]; - - good: data[0..=5] == [0, 1, 2, 3, 4, 5]; - good: data[{ - let mut iter = 0..=5; - iter.by_ref().count(); // exhaust it - iter - }] == []; - - // 0..=6 is out of range before exhaustion, so it - // stands to reason that it still would be after. - bad: data[{ - let mut iter = 0..=6; - iter.by_ref().count(); // exhaust it - iter - }]; - message: "out of range"; - } - } - - panic_cases! { - in mod range_neg_width { - data: [0, 1, 2, 3, 4, 5]; - - good: data[4..4] == []; - bad: data[4..3]; - message: "but ends at"; - } - - in mod rangeinclusive_neg_width { - data: [0, 1, 2, 3, 4, 5]; - - good: data[4..=3] == []; - bad: data[4..=2]; - message: "but ends at"; - } - - in mod boundpair_neg_width { - data: [0, 1, 2, 3, 4, 5]; - - good: data[(Bound::Included(4), Bound::Excluded(4))] == []; - bad: data[(Bound::Included(4), Bound::Excluded(3))]; - message: "but ends at"; - } - } - - panic_cases! { - in mod rangeinclusive_overflow { - data: [0, 1]; - - // note: using 0 specifically ensures that the result of overflowing is 0..0, - // so that `get` doesn't simply return None for the wrong reason. - bad: data[0 ..= usize::MAX]; - message: "maximum usize"; - } - - in mod rangetoinclusive_overflow { - data: [0, 1]; - - bad: data[..= usize::MAX]; - message: "maximum usize"; - } - - in mod boundpair_overflow_end { - data: [0; 1]; - - bad: data[(Bound::Unbounded, Bound::Included(usize::MAX))]; - message: "maximum usize"; - } - - in mod boundpair_overflow_start { - data: [0; 1]; - - bad: data[(Bound::Excluded(usize::MAX), Bound::Unbounded)]; - message: "maximum usize"; - } - } // panic_cases! -} - -#[test] -fn test_find_rfind() { - let v = [0, 1, 2, 3, 4, 5]; - let mut iter = v.iter(); - let mut i = v.len(); - while let Some(&elt) = iter.rfind(|_| true) { - i -= 1; - assert_eq!(elt, v[i]); - } - assert_eq!(i, 0); - assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3)); -} - -#[test] -fn test_iter_folds() { - let a = [1, 2, 3, 4, 5]; // len>4 so the unroll is used - assert_eq!(a.iter().fold(0, |acc, &x| 2 * acc + x), 57); - assert_eq!(a.iter().rfold(0, |acc, &x| 2 * acc + x), 129); - let fold = |acc: i32, &x| acc.checked_mul(2)?.checked_add(x); - assert_eq!(a.iter().try_fold(0, &fold), Some(57)); - assert_eq!(a.iter().try_rfold(0, &fold), Some(129)); - - // short-circuiting try_fold, through other methods - let a = [0, 1, 2, 3, 5, 5, 5, 7, 8, 9]; - let mut iter = a.iter(); - assert_eq!(iter.position(|&x| x == 3), Some(3)); - assert_eq!(iter.rfind(|&&x| x == 5), Some(&5)); - assert_eq!(iter.len(), 2); -} - -#[test] -fn test_rotate_left() { - const N: usize = 600; - let a: &mut [_] = &mut [0; N]; - for i in 0..N { - a[i] = i; - } - - a.rotate_left(42); - let k = N - 42; - - for i in 0..N { - assert_eq!(a[(i + k) % N], i); - } -} - -#[test] -fn test_rotate_right() { - const N: usize = 600; - let a: &mut [_] = &mut [0; N]; - for i in 0..N { - a[i] = i; - } - - a.rotate_right(42); - - for i in 0..N { - assert_eq!(a[(i + 42) % N], i); - } -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn brute_force_rotate_test_0() { - // In case of edge cases involving multiple algorithms - let n = 300; - for len in 0..n { - for s in 0..len { - let mut v = Vec::with_capacity(len); - for i in 0..len { - v.push(i); - } - v[..].rotate_right(s); - for i in 0..v.len() { - assert_eq!(v[i], v.len().wrapping_add(i.wrapping_sub(s)) % v.len()); - } - } - } -} - -#[test] -fn brute_force_rotate_test_1() { - // `ptr_rotate` covers so many kinds of pointer usage, that this is just a good test for - // pointers in general. This uses a `[usize; 4]` to hit all algorithms without overwhelming miri - let n = 30; - for len in 0..n { - for s in 0..len { - let mut v: Vec<[usize; 4]> = Vec::with_capacity(len); - for i in 0..len { - v.push([i, 0, 0, 0]); - } - v[..].rotate_right(s); - for i in 0..v.len() { - assert_eq!(v[i][0], v.len().wrapping_add(i.wrapping_sub(s)) % v.len()); - } - } - } -} - -#[test] -#[cfg(not(target_arch = "wasm32"))] -#[cfg_attr(miri, ignore)] // Miri is too slow -fn select_nth_unstable() { - use core::cmp::Ordering::{Equal, Greater, Less}; - - use rand::Rng; - use rand::seq::SliceRandom; - - let mut rng = crate::test_rng(); - - for len in (2..21).chain(500..501) { - let mut orig = vec![0; len]; - - for &modulus in &[5, 10, 1000] { - for _ in 0..10 { - for i in 0..len { - orig[i] = rng.gen::() % modulus; - } - - let v_sorted = { - let mut v = orig.clone(); - v.sort(); - v - }; - - // Sort in default order. - for pivot in 0..len { - let mut v = orig.clone(); - v.select_nth_unstable(pivot); - - assert_eq!(v_sorted[pivot], v[pivot]); - for i in 0..pivot { - for j in pivot..len { - assert!(v[i] <= v[j]); - } - } - } - - // Sort in ascending order. - for pivot in 0..len { - let mut v = orig.clone(); - let (left, pivot, right) = v.select_nth_unstable_by(pivot, |a, b| a.cmp(b)); - - assert_eq!(left.len() + right.len(), len - 1); - - for l in left { - assert!(l <= pivot); - for r in right.iter_mut() { - assert!(l <= r); - assert!(pivot <= r); - } - } - } - - // Sort in descending order. - let sort_descending_comparator = |a: &i32, b: &i32| b.cmp(a); - let v_sorted_descending = { - let mut v = orig.clone(); - v.sort_by(sort_descending_comparator); - v - }; - - for pivot in 0..len { - let mut v = orig.clone(); - v.select_nth_unstable_by(pivot, sort_descending_comparator); - - assert_eq!(v_sorted_descending[pivot], v[pivot]); - for i in 0..pivot { - for j in pivot..len { - assert!(v[j] <= v[i]); - } - } - } - } - } - } - - // Sort at index using a completely random comparison function. - // This will reorder the elements *somehow*, but won't panic. - let mut v = [0; 500]; - for i in 0..v.len() { - v[i] = i as i32; - } - - for pivot in 0..v.len() { - v.select_nth_unstable_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); - v.sort(); - for i in 0..v.len() { - assert_eq!(v[i], i as i32); - } - } - - // Should not panic. - [(); 10].select_nth_unstable(0); - [(); 10].select_nth_unstable(5); - [(); 10].select_nth_unstable(9); - [(); 100].select_nth_unstable(0); - [(); 100].select_nth_unstable(50); - [(); 100].select_nth_unstable(99); - - let mut v = [0xDEADBEEFu64]; - v.select_nth_unstable(0); - assert!(v == [0xDEADBEEF]); -} - -#[test] -#[should_panic(expected = "index 0 greater than length of slice")] -fn select_nth_unstable_zero_length() { - [0i32; 0].select_nth_unstable(0); -} - -#[test] -#[should_panic(expected = "index 20 greater than length of slice")] -fn select_nth_unstable_past_length() { - [0i32; 10].select_nth_unstable(20); -} - -pub mod memchr { - use core::slice::memchr::{memchr, memrchr}; - - // test fallback implementations on all platforms - #[test] - fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); - } - - #[test] - fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); - } - - #[test] - fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); - } - - #[test] - fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); - } - - #[test] - fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); - } - - #[test] - fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); - } - - #[test] - fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); - } - - #[test] - fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); - } - - #[test] - fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); - } - - #[test] - fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); - } - - #[test] - fn each_alignment_reversed() { - let mut data = [1u8; 64]; - let needle = 2; - let pos = 40; - data[pos] = needle; - for start in 0..16 { - assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); - } - } -} - -#[test] -fn test_align_to_simple() { - let bytes = [1u8, 2, 3, 4, 5, 6, 7]; - let (prefix, aligned, suffix) = unsafe { bytes.align_to::() }; - assert_eq!(aligned.len(), 3); - assert!(prefix == [1] || suffix == [7]); - let expect1 = [1 << 8 | 2, 3 << 8 | 4, 5 << 8 | 6]; - let expect2 = [1 | 2 << 8, 3 | 4 << 8, 5 | 6 << 8]; - let expect3 = [2 << 8 | 3, 4 << 8 | 5, 6 << 8 | 7]; - let expect4 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8]; - assert!( - aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4, - "aligned={:?} expected={:?} || {:?} || {:?} || {:?}", - aligned, - expect1, - expect2, - expect3, - expect4 - ); -} - -#[test] -fn test_align_to_zst() { - let bytes = [1, 2, 3, 4, 5, 6, 7]; - let (prefix, aligned, suffix) = unsafe { bytes.align_to::<()>() }; - assert_eq!(aligned.len(), 0); - assert!(prefix == [1, 2, 3, 4, 5, 6, 7] || suffix == [1, 2, 3, 4, 5, 6, 7]); -} - -#[test] -fn test_align_to_non_trivial() { - #[repr(align(8))] - struct U64(#[allow(dead_code)] u64, #[allow(dead_code)] u64); - #[repr(align(8))] - struct U64U64U32(#[allow(dead_code)] u64, #[allow(dead_code)] u64, #[allow(dead_code)] u32); - let data = [ - U64(1, 2), - U64(3, 4), - U64(5, 6), - U64(7, 8), - U64(9, 10), - U64(11, 12), - U64(13, 14), - U64(15, 16), - ]; - let (prefix, aligned, suffix) = unsafe { data.align_to::() }; - assert_eq!(aligned.len(), 4); - assert_eq!(prefix.len() + suffix.len(), 2); -} - -#[test] -fn test_align_to_empty_mid() { - use core::mem; - - // Make sure that we do not create empty unaligned slices for the mid part, even when the - // overall slice is too short to contain an aligned address. - let bytes = [1, 2, 3, 4, 5, 6, 7]; - type Chunk = u32; - for offset in 0..4 { - let (_, mid, _) = unsafe { bytes[offset..offset + 1].align_to::() }; - assert_eq!(mid.as_ptr() as usize % mem::align_of::(), 0); - } -} - -#[test] -fn test_align_to_mut_aliasing() { - let mut val = [1u8, 2, 3, 4, 5]; - // `align_to_mut` used to create `mid` in a way that there was some intermediate - // incorrect aliasing, invalidating the resulting `mid` slice. - let (begin, mid, end) = unsafe { val.align_to_mut::<[u8; 2]>() }; - assert!(begin.len() == 0); - assert!(end.len() == 1); - mid[0] = mid[1]; - assert_eq!(val, [3, 4, 3, 4, 5]) -} - -#[test] -fn test_slice_partition_dedup_by() { - let mut slice: [i32; 9] = [1, -1, 2, 3, 1, -5, 5, -2, 2]; - - let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.abs() == b.abs()); - - assert_eq!(dedup, [1, 2, 3, 1, -5, -2]); - assert_eq!(duplicates, [5, -1, 2]); -} - -#[test] -fn test_slice_partition_dedup_empty() { - let mut slice: [i32; 0] = []; - - let (dedup, duplicates) = slice.partition_dedup(); - - assert_eq!(dedup, []); - assert_eq!(duplicates, []); -} - -#[test] -fn test_slice_partition_dedup_one() { - let mut slice = [12]; - - let (dedup, duplicates) = slice.partition_dedup(); - - assert_eq!(dedup, [12]); - assert_eq!(duplicates, []); -} - -#[test] -fn test_slice_partition_dedup_multiple_ident() { - let mut slice = [12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11]; - - let (dedup, duplicates) = slice.partition_dedup(); - - assert_eq!(dedup, [12, 11]); - assert_eq!(duplicates, [12, 12, 12, 12, 11, 11, 11, 11, 11]); -} - -#[test] -fn test_slice_partition_dedup_partialeq() { - #[derive(Debug)] - struct Foo(i32, #[allow(dead_code)] i32); - - impl PartialEq for Foo { - fn eq(&self, other: &Foo) -> bool { - self.0 == other.0 - } - } - - let mut slice = [Foo(0, 1), Foo(0, 5), Foo(1, 7), Foo(1, 9)]; - - let (dedup, duplicates) = slice.partition_dedup(); - - assert_eq!(dedup, [Foo(0, 1), Foo(1, 7)]); - assert_eq!(duplicates, [Foo(0, 5), Foo(1, 9)]); -} - -#[test] -fn test_copy_within() { - // Start to end, with a RangeTo. - let mut bytes = *b"Hello, World!"; - bytes.copy_within(..3, 10); - assert_eq!(&bytes, b"Hello, WorHel"); - - // End to start, with a RangeFrom. - let mut bytes = *b"Hello, World!"; - bytes.copy_within(10.., 0); - assert_eq!(&bytes, b"ld!lo, World!"); - - // Overlapping, with a RangeInclusive. - let mut bytes = *b"Hello, World!"; - bytes.copy_within(0..=11, 1); - assert_eq!(&bytes, b"HHello, World"); - - // Whole slice, with a RangeFull. - let mut bytes = *b"Hello, World!"; - bytes.copy_within(.., 0); - assert_eq!(&bytes, b"Hello, World!"); - - // Ensure that copying at the end of slice won't cause UB. - let mut bytes = *b"Hello, World!"; - bytes.copy_within(13..13, 5); - assert_eq!(&bytes, b"Hello, World!"); - bytes.copy_within(5..5, 13); - assert_eq!(&bytes, b"Hello, World!"); -} - -#[test] -#[should_panic(expected = "range end index 14 out of range for slice of length 13")] -fn test_copy_within_panics_src_too_long() { - let mut bytes = *b"Hello, World!"; - // The length is only 13, so 14 is out of bounds. - bytes.copy_within(10..14, 0); -} - -#[test] -#[should_panic(expected = "dest is out of bounds")] -fn test_copy_within_panics_dest_too_long() { - let mut bytes = *b"Hello, World!"; - // The length is only 13, so a slice of length 4 starting at index 10 is out of bounds. - bytes.copy_within(0..4, 10); -} - -#[test] -#[should_panic(expected = "slice index starts at 2 but ends at 1")] -fn test_copy_within_panics_src_inverted() { - let mut bytes = *b"Hello, World!"; - // 2 is greater than 1, so this range is invalid. - bytes.copy_within(2..1, 0); -} -#[test] -#[should_panic(expected = "attempted to index slice up to maximum usize")] -fn test_copy_within_panics_src_out_of_bounds() { - let mut bytes = *b"Hello, World!"; - // an inclusive range ending at usize::MAX would make src_end overflow - bytes.copy_within(usize::MAX..=usize::MAX, 0); -} - -#[test] -fn test_is_sorted() { - let empty: [i32; 0] = []; - - // Tests on integers - assert!([1, 2, 2, 9].is_sorted()); - assert!(![1, 3, 2].is_sorted()); - assert!([0].is_sorted()); - assert!([0, 0].is_sorted()); - assert!(empty.is_sorted()); - - // Tests on floats - assert!([1.0f32, 2.0, 2.0, 9.0].is_sorted()); - assert!(![1.0f32, 3.0f32, 2.0f32].is_sorted()); - assert!([0.0f32].is_sorted()); - assert!([0.0f32, 0.0f32].is_sorted()); - // Test cases with NaNs - assert!([f32::NAN].is_sorted()); - assert!(![f32::NAN, f32::NAN].is_sorted()); - assert!(![0.0, 1.0, f32::NAN].is_sorted()); - // Tests from - assert!(![f32::NAN, f32::NAN, f32::NAN].is_sorted()); - assert!(![1.0, f32::NAN, 2.0].is_sorted()); - assert!(![2.0, f32::NAN, 1.0].is_sorted()); - assert!(![2.0, f32::NAN, 1.0, 7.0].is_sorted()); - assert!(![2.0, f32::NAN, 1.0, 0.0].is_sorted()); - assert!(![-f32::NAN, -1.0, 0.0, 1.0, f32::NAN].is_sorted()); - assert!(![f32::NAN, -f32::NAN, -1.0, 0.0, 1.0].is_sorted()); - assert!(![1.0, f32::NAN, -f32::NAN, -1.0, 0.0].is_sorted()); - assert!(![0.0, 1.0, f32::NAN, -f32::NAN, -1.0].is_sorted()); - assert!(![-1.0, 0.0, 1.0, f32::NAN, -f32::NAN].is_sorted()); - - // Tests for is_sorted_by - assert!(![6, 2, 8, 5, 1, -60, 1337].is_sorted()); - assert!([6, 2, 8, 5, 1, -60, 1337].is_sorted_by(|_, _| true)); - - // Tests for is_sorted_by_key - assert!([-2, -1, 0, 3].is_sorted()); - assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); - assert!(!["c", "bb", "aaa"].is_sorted()); - assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); -} - -#[test] -fn test_slice_run_destructors() { - // Make sure that destructors get run on slice literals - struct Foo<'a> { - x: &'a Cell, - } - - impl<'a> Drop for Foo<'a> { - fn drop(&mut self) { - self.x.set(self.x.get() + 1); - } - } - - fn foo(x: &Cell) -> Foo<'_> { - Foo { x } - } - - let x = &Cell::new(0); - - { - let l = &[foo(x)]; - assert_eq!(l[0].x.get(), 0); - } - - assert_eq!(x.get(), 1); -} - -#[test] -fn test_const_from_ref() { - const VALUE: &i32 = &1; - const SLICE: &[i32] = core::slice::from_ref(VALUE); - - assert!(core::ptr::eq(VALUE, &SLICE[0])) -} - -#[test] -fn test_slice_fill_with_uninit() { - // This should not UB. See #87891 - let mut a = [MaybeUninit::::uninit(); 10]; - a.fill(MaybeUninit::uninit()); -} - -#[test] -fn test_swap() { - let mut x = ["a", "b", "c", "d"]; - x.swap(1, 3); - assert_eq!(x, ["a", "d", "c", "b"]); - x.swap(0, 3); - assert_eq!(x, ["b", "d", "c", "a"]); -} - -mod swap_panics { - #[test] - #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")] - fn index_a_equals_len() { - let mut x = ["a", "b", "c", "d"]; - x.swap(4, 2); - } - - #[test] - #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")] - fn index_b_equals_len() { - let mut x = ["a", "b", "c", "d"]; - x.swap(2, 4); - } - - #[test] - #[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")] - fn index_a_greater_than_len() { - let mut x = ["a", "b", "c", "d"]; - x.swap(5, 2); - } - - #[test] - #[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")] - fn index_b_greater_than_len() { - let mut x = ["a", "b", "c", "d"]; - x.swap(2, 5); - } -} - -#[test] -fn slice_split_first_chunk_mut() { - let v = &mut [1, 2, 3, 4, 5, 6][..]; - - { - let (left, right) = v.split_first_chunk_mut::<0>().unwrap(); - assert_eq!(left, &mut []); - assert_eq!(right, [1, 2, 3, 4, 5, 6]); - } - - { - let (left, right) = v.split_first_chunk_mut::<6>().unwrap(); - assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); - assert_eq!(right, []); - } - - { - assert!(v.split_first_chunk_mut::<7>().is_none()); - } -} - -#[test] -fn slice_split_last_chunk_mut() { - let v = &mut [1, 2, 3, 4, 5, 6][..]; - - { - let (left, right) = v.split_last_chunk_mut::<0>().unwrap(); - assert_eq!(left, [1, 2, 3, 4, 5, 6]); - assert_eq!(right, &mut []); - } - - { - let (left, right) = v.split_last_chunk_mut::<6>().unwrap(); - assert_eq!(left, []); - assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); - } - - { - assert!(v.split_last_chunk_mut::<7>().is_none()); - } -} - -#[test] -fn split_as_slice() { - let arr = [1, 2, 3, 4, 5, 6]; - let mut split = arr.split(|v| v % 2 == 0); - assert_eq!(split.as_slice(), &[1, 2, 3, 4, 5, 6]); - assert!(split.next().is_some()); - assert_eq!(split.as_slice(), &[3, 4, 5, 6]); - assert!(split.next().is_some()); - assert!(split.next().is_some()); - assert_eq!(split.as_slice(), &[]); -} - -#[test] -fn slice_split_once() { - let v = &[1, 2, 3, 2, 4][..]; - - assert_eq!(v.split_once(|&x| x == 2), Some((&[1][..], &[3, 2, 4][..]))); - assert_eq!(v.split_once(|&x| x == 1), Some((&[][..], &[2, 3, 2, 4][..]))); - assert_eq!(v.split_once(|&x| x == 4), Some((&[1, 2, 3, 2][..], &[][..]))); - assert_eq!(v.split_once(|&x| x == 0), None); -} - -#[test] -fn slice_rsplit_once() { - let v = &[1, 2, 3, 2, 4][..]; - - assert_eq!(v.rsplit_once(|&x| x == 2), Some((&[1, 2, 3][..], &[4][..]))); - assert_eq!(v.rsplit_once(|&x| x == 1), Some((&[][..], &[2, 3, 2, 4][..]))); - assert_eq!(v.rsplit_once(|&x| x == 4), Some((&[1, 2, 3, 2][..], &[][..]))); - assert_eq!(v.rsplit_once(|&x| x == 0), None); -} - -macro_rules! take_tests { - (slice: &[], $($tts:tt)*) => { - take_tests!(ty: &[()], slice: &[], $($tts)*); - }; - (slice: &mut [], $($tts:tt)*) => { - take_tests!(ty: &mut [()], slice: &mut [], $($tts)*); - }; - (slice: &$slice:expr, $($tts:tt)*) => { - take_tests!(ty: &[_], slice: &$slice, $($tts)*); - }; - (slice: &mut $slice:expr, $($tts:tt)*) => { - take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*); - }; - (ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => { - $( - #[test] - fn $test_name() { - let mut slice: $ty = $slice; - assert_eq!($output, slice.$method($($args)*)); - let remaining: $ty = $remaining; - assert_eq!(remaining, slice); - } - )* - }; -} - -take_tests! { - slice: &[0, 1, 2, 3], method: take, - (take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]), - (take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]), - (take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]), - (take_oob_range_to, (..5), None, &[0, 1, 2, 3]), - (take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]), - (take_oob_range_from, (5..), None, &[0, 1, 2, 3]), -} - -take_tests! { - slice: &mut [0, 1, 2, 3], method: take_mut, - (take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]), - (take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]), - (take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]), - (take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]), - (take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]), - (take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]), -} - -take_tests! { - slice: &[1, 2], method: take_first, - (take_first_nonempty, (), Some(&1), &[2]), -} - -take_tests! { - slice: &mut [1, 2], method: take_first_mut, - (take_first_mut_nonempty, (), Some(&mut 1), &mut [2]), -} - -take_tests! { - slice: &[1, 2], method: take_last, - (take_last_nonempty, (), Some(&2), &[1]), -} - -take_tests! { - slice: &mut [1, 2], method: take_last_mut, - (take_last_mut_nonempty, (), Some(&mut 2), &mut [1]), -} - -take_tests! { - slice: &[], method: take_first, - (take_first_empty, (), None, &[]), -} - -take_tests! { - slice: &mut [], method: take_first_mut, - (take_first_mut_empty, (), None, &mut []), -} - -take_tests! { - slice: &[], method: take_last, - (take_last_empty, (), None, &[]), -} - -take_tests! { - slice: &mut [], method: take_last_mut, - (take_last_mut_empty, (), None, &mut []), -} - -#[cfg(not(miri))] // unused in Miri -const EMPTY_MAX: &'static [()] = &[(); usize::MAX]; - -// can't be a constant due to const mutability rules -#[cfg(not(miri))] // unused in Miri -macro_rules! empty_max_mut { - () => { - &mut [(); usize::MAX] as _ - }; -} - -#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) -take_tests! { - slice: &[(); usize::MAX], method: take, - (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]), - (take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX), - (take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX), -} - -#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) -take_tests! { - slice: &mut [(); usize::MAX], method: take_mut, - (take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]), - (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), - (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), -} - -#[test] -fn test_slice_from_ptr_range() { - let arr = ["foo".to_owned(), "bar".to_owned()]; - let range = arr.as_ptr_range(); - unsafe { - assert_eq!(slice::from_ptr_range(range), &arr); - } - - let mut arr = [1, 2, 3]; - let range = arr.as_mut_ptr_range(); - unsafe { - assert_eq!(slice::from_mut_ptr_range(range), &mut [1, 2, 3]); - } - - let arr: [Vec; 0] = []; - let range = arr.as_ptr_range(); - unsafe { - assert_eq!(slice::from_ptr_range(range), &arr); - } -} - -#[test] -#[should_panic = "slice len overflow"] -fn test_flatten_size_overflow() { - let x = &[[(); usize::MAX]; 2][..]; - let _ = x.as_flattened(); -} - -#[test] -#[should_panic = "slice len overflow"] -fn test_flatten_mut_size_overflow() { - let x = &mut [[(); usize::MAX]; 2][..]; - let _ = x.as_flattened_mut(); -} - -#[test] -fn test_get_many_mut_normal_2() { - let mut v = vec![1, 2, 3, 4, 5]; - let [a, b] = v.get_many_mut([3, 0]).unwrap(); - *a += 10; - *b += 100; - assert_eq!(v, vec![101, 2, 3, 14, 5]); - - let [a, b] = v.get_many_mut([0..=1, 2..=2]).unwrap(); - assert_eq!(a, &mut [101, 2][..]); - assert_eq!(b, &mut [3][..]); - a[0] += 10; - a[1] += 20; - b[0] += 100; - assert_eq!(v, vec![111, 22, 103, 14, 5]); -} - -#[test] -fn test_get_many_mut_normal_3() { - let mut v = vec![1, 2, 3, 4, 5]; - let [a, b, c] = v.get_many_mut([0, 4, 2]).unwrap(); - *a += 10; - *b += 100; - *c += 1000; - assert_eq!(v, vec![11, 2, 1003, 4, 105]); - - let [a, b, c] = v.get_many_mut([0..1, 4..5, 1..4]).unwrap(); - assert_eq!(a, &mut [11][..]); - assert_eq!(b, &mut [105][..]); - assert_eq!(c, &mut [2, 1003, 4][..]); - a[0] += 10; - b[0] += 100; - c[0] += 1000; - assert_eq!(v, vec![21, 1002, 1003, 4, 205]); -} - -#[test] -fn test_get_many_mut_empty() { - let mut v = vec![1, 2, 3, 4, 5]; - let [] = v.get_many_mut::([]).unwrap(); - let [] = v.get_many_mut::, 0>([]).unwrap(); - let [] = v.get_many_mut::, 0>([]).unwrap(); - assert_eq!(v, vec![1, 2, 3, 4, 5]); -} - -#[test] -fn test_get_many_mut_single_first() { - let mut v = vec![1, 2, 3, 4, 5]; - let [a] = v.get_many_mut([0]).unwrap(); - *a += 10; - assert_eq!(v, vec![11, 2, 3, 4, 5]); -} - -#[test] -fn test_get_many_mut_single_last() { - let mut v = vec![1, 2, 3, 4, 5]; - let [a] = v.get_many_mut([4]).unwrap(); - *a += 10; - assert_eq!(v, vec![1, 2, 3, 4, 15]); -} - -#[test] -fn test_get_many_mut_oob_nonempty() { - let mut v = vec![1, 2, 3, 4, 5]; - assert!(v.get_many_mut([5]).is_err()); -} - -#[test] -fn test_get_many_mut_oob_empty() { - let mut v: Vec = vec![]; - assert!(v.get_many_mut([0]).is_err()); -} - -#[test] -fn test_get_many_mut_duplicate() { - let mut v = vec![1, 2, 3, 4, 5]; - assert!(v.get_many_mut([1, 3, 3, 4]).is_err()); -} - -#[test] -fn test_get_many_mut_range_oob() { - let mut v = vec![1, 2, 3, 4, 5]; - assert!(v.get_many_mut([0..6]).is_err()); - assert!(v.get_many_mut([5..6]).is_err()); - assert!(v.get_many_mut([6..6]).is_err()); - assert!(v.get_many_mut([0..=5]).is_err()); - assert!(v.get_many_mut([0..=6]).is_err()); - assert!(v.get_many_mut([5..=5]).is_err()); -} - -#[test] -fn test_get_many_mut_range_overlapping() { - let mut v = vec![1, 2, 3, 4, 5]; - assert!(v.get_many_mut([0..1, 0..2]).is_err()); - assert!(v.get_many_mut([0..1, 1..2, 0..1]).is_err()); - assert!(v.get_many_mut([0..3, 1..1]).is_err()); - assert!(v.get_many_mut([0..3, 1..2]).is_err()); - assert!(v.get_many_mut([0..=0, 2..=2, 0..=1]).is_err()); - assert!(v.get_many_mut([0..=4, 0..=0]).is_err()); - assert!(v.get_many_mut([4..=4, 0..=0, 3..=4]).is_err()); -} - -#[test] -fn test_get_many_mut_range_empty_at_edge() { - let mut v = vec![1, 2, 3, 4, 5]; - assert_eq!( - v.get_many_mut([0..0, 0..5, 5..5]), - Ok([&mut [][..], &mut [1, 2, 3, 4, 5], &mut []]), - ); - assert_eq!( - v.get_many_mut([0..0, 0..1, 1..1, 1..2, 2..2, 2..3, 3..3, 3..4, 4..4, 4..5, 5..5]), - Ok([ - &mut [][..], - &mut [1], - &mut [], - &mut [2], - &mut [], - &mut [3], - &mut [], - &mut [4], - &mut [], - &mut [5], - &mut [], - ]), - ); -} - -#[test] -fn test_slice_from_raw_parts_in_const() { - static FANCY: i32 = 4; - static FANCY_SLICE: &[i32] = unsafe { std::slice::from_raw_parts(&FANCY, 1) }; - assert_eq!(FANCY_SLICE.as_ptr(), std::ptr::addr_of!(FANCY)); - assert_eq!(FANCY_SLICE.len(), 1); - - const EMPTY_SLICE: &[i32] = - unsafe { std::slice::from_raw_parts(std::ptr::without_provenance(123456), 0) }; - assert_eq!(EMPTY_SLICE.as_ptr().addr(), 123456); - assert_eq!(EMPTY_SLICE.len(), 0); -} diff --git a/library/core/tests/str.rs b/library/core/tests/str.rs deleted file mode 100644 index f5066343af2..00000000000 --- a/library/core/tests/str.rs +++ /dev/null @@ -1 +0,0 @@ -// All `str` tests live in library/alloc/tests/str.rs diff --git a/library/core/tests/str_lossy.rs b/library/core/tests/str_lossy.rs deleted file mode 100644 index 6e70ea3e285..00000000000 --- a/library/core/tests/str_lossy.rs +++ /dev/null @@ -1,83 +0,0 @@ -#[test] -fn chunks() { - macro_rules! assert_chunks { - ( $string:expr, $(($valid:expr, $invalid:expr)),* $(,)? ) => {{ - let mut iter = $string.utf8_chunks(); - $( - let chunk = iter.next().expect("missing chunk"); - assert_eq!($valid, chunk.valid()); - assert_eq!($invalid, chunk.invalid()); - )* - assert_eq!(None, iter.next()); - }}; - } - - assert_chunks!(b"hello", ("hello", b"")); - assert_chunks!("ศไทย中华Việt Nam".as_bytes(), ("ศไทย中华Việt Nam", b"")); - assert_chunks!( - b"Hello\xC2 There\xFF Goodbye", - ("Hello", b"\xC2"), - (" There", b"\xFF"), - (" Goodbye", b""), - ); - assert_chunks!( - b"Hello\xC0\x80 There\xE6\x83 Goodbye", - ("Hello", b"\xC0"), - ("", b"\x80"), - (" There", b"\xE6\x83"), - (" Goodbye", b""), - ); - assert_chunks!( - b"\xF5foo\xF5\x80bar", - ("", b"\xF5"), - ("foo", b"\xF5"), - ("", b"\x80"), - ("bar", b""), - ); - assert_chunks!( - b"\xF1foo\xF1\x80bar\xF1\x80\x80baz", - ("", b"\xF1"), - ("foo", b"\xF1\x80"), - ("bar", b"\xF1\x80\x80"), - ("baz", b""), - ); - assert_chunks!( - b"\xF4foo\xF4\x80bar\xF4\xBFbaz", - ("", b"\xF4"), - ("foo", b"\xF4\x80"), - ("bar", b"\xF4"), - ("", b"\xBF"), - ("baz", b""), - ); - assert_chunks!( - b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar", - ("", b"\xF0"), - ("", b"\x80"), - ("", b"\x80"), - ("", b"\x80"), - ("foo\u{10000}bar", b""), - ); - - // surrogates - assert_chunks!( - b"\xED\xA0\x80foo\xED\xBF\xBFbar", - ("", b"\xED"), - ("", b"\xA0"), - ("", b"\x80"), - ("foo", b"\xED"), - ("", b"\xBF"), - ("", b"\xBF"), - ("bar", b""), - ); -} - -#[test] -fn debug() { - assert_eq!( - "\"Hello\\xC0\\x80 There\\xE6\\x83 Goodbye\\u{10d4ea}\"", - &format!( - "{:?}", - b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa".utf8_chunks().debug(), - ), - ); -} diff --git a/library/core/tests/task.rs b/library/core/tests/task.rs deleted file mode 100644 index 163b34c9648..00000000000 --- a/library/core/tests/task.rs +++ /dev/null @@ -1,25 +0,0 @@ -use core::task::{Poll, RawWaker, RawWakerVTable, Waker}; - -#[test] -fn poll_const() { - // test that the methods of `Poll` are usable in a const context - - const POLL: Poll = Poll::Pending; - - const IS_READY: bool = POLL.is_ready(); - assert!(!IS_READY); - - const IS_PENDING: bool = POLL.is_pending(); - assert!(IS_PENDING); -} - -#[test] -fn waker_const() { - const VOID_TABLE: RawWakerVTable = RawWakerVTable::new(|_| VOID_WAKER, |_| {}, |_| {}, |_| {}); - - const VOID_WAKER: RawWaker = RawWaker::new(&(), &VOID_TABLE); - - static WAKER: Waker = unsafe { Waker::from_raw(VOID_WAKER) }; - - WAKER.wake_by_ref(); -} diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs deleted file mode 100644 index fe7bb11c675..00000000000 --- a/library/core/tests/time.rs +++ /dev/null @@ -1,564 +0,0 @@ -use core::time::Duration; - -#[test] -fn creation() { - assert_ne!(Duration::from_secs(1), Duration::from_secs(0)); - assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), Duration::from_secs(3)); - assert_eq!( - Duration::from_millis(10) + Duration::from_secs(4), - Duration::new(4, 10 * 1_000_000) - ); - assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); -} - -#[test] -#[should_panic] -fn new_overflow() { - let _ = Duration::new(u64::MAX, 1_000_000_000); -} - -#[test] -#[should_panic] -fn from_mins_overflow() { - let overflow = u64::MAX / 60 + 1; - let _ = Duration::from_mins(overflow); -} - -#[test] -#[should_panic] -fn from_hours_overflow() { - let overflow = u64::MAX / (60 * 60) + 1; - let _ = Duration::from_hours(overflow); -} - -#[test] -#[should_panic] -fn from_days_overflow() { - let overflow = u64::MAX / (24 * 60 * 60) + 1; - let _ = Duration::from_days(overflow); -} - -#[test] -#[should_panic] -fn from_weeks_overflow() { - let overflow = u64::MAX / (7 * 24 * 60 * 60) + 1; - let _ = Duration::from_weeks(overflow); -} - -#[test] -fn constructors() { - assert_eq!(Duration::from_weeks(1), Duration::from_secs(7 * 24 * 60 * 60)); - assert_eq!(Duration::from_weeks(0), Duration::ZERO); - - assert_eq!(Duration::from_days(1), Duration::from_secs(86_400)); - assert_eq!(Duration::from_days(0), Duration::ZERO); - - assert_eq!(Duration::from_hours(1), Duration::from_secs(3_600)); - assert_eq!(Duration::from_hours(0), Duration::ZERO); - - assert_eq!(Duration::from_mins(1), Duration::from_secs(60)); - assert_eq!(Duration::from_mins(0), Duration::ZERO); -} - -#[test] -fn secs() { - assert_eq!(Duration::new(0, 0).as_secs(), 0); - assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0); - assert_eq!(Duration::new(0, 1_050_000_001).as_secs(), 1); - assert_eq!(Duration::from_secs(1).as_secs(), 1); - assert_eq!(Duration::from_millis(999).as_secs(), 0); - assert_eq!(Duration::from_millis(1001).as_secs(), 1); - assert_eq!(Duration::from_micros(999_999).as_secs(), 0); - assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1); - assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0); - assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1); -} - -#[test] -fn millis() { - assert_eq!(Duration::new(0, 0).subsec_millis(), 0); - assert_eq!(Duration::new(0, 500_000_005).subsec_millis(), 500); - assert_eq!(Duration::new(0, 1_050_000_001).subsec_millis(), 50); - assert_eq!(Duration::from_secs(1).subsec_millis(), 0); - assert_eq!(Duration::from_millis(999).subsec_millis(), 999); - assert_eq!(Duration::from_millis(1001).subsec_millis(), 1); - assert_eq!(Duration::from_micros(999_999).subsec_millis(), 999); - assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1); - assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999); - assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1); -} - -#[test] -fn micros() { - assert_eq!(Duration::new(0, 0).subsec_micros(), 0); - assert_eq!(Duration::new(0, 500_000_005).subsec_micros(), 500_000); - assert_eq!(Duration::new(0, 1_050_000_001).subsec_micros(), 50_000); - assert_eq!(Duration::from_secs(1).subsec_micros(), 0); - assert_eq!(Duration::from_millis(999).subsec_micros(), 999_000); - assert_eq!(Duration::from_millis(1001).subsec_micros(), 1_000); - assert_eq!(Duration::from_micros(999_999).subsec_micros(), 999_999); - assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1); - assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999); - assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1); -} - -#[test] -fn nanos() { - assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); - assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); - assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); - assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); - assert_eq!(Duration::from_millis(999).subsec_nanos(), 999_000_000); - assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1_000_000); - assert_eq!(Duration::from_micros(999_999).subsec_nanos(), 999_999_000); - assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000); - assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999); - assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1); -} - -#[test] -fn abs_diff() { - assert_eq!(Duration::new(2, 0).abs_diff(Duration::new(1, 0)), Duration::new(1, 0)); - assert_eq!(Duration::new(1, 0).abs_diff(Duration::new(2, 0)), Duration::new(1, 0)); - assert_eq!(Duration::new(1, 0).abs_diff(Duration::new(1, 0)), Duration::new(0, 0)); - assert_eq!(Duration::new(1, 1).abs_diff(Duration::new(0, 2)), Duration::new(0, 999_999_999)); - assert_eq!(Duration::new(1, 1).abs_diff(Duration::new(2, 1)), Duration::new(1, 0)); - assert_eq!(Duration::MAX.abs_diff(Duration::MAX), Duration::ZERO); - assert_eq!(Duration::ZERO.abs_diff(Duration::ZERO), Duration::ZERO); - assert_eq!(Duration::MAX.abs_diff(Duration::ZERO), Duration::MAX); - assert_eq!(Duration::ZERO.abs_diff(Duration::MAX), Duration::MAX); -} - -#[test] -fn add() { - assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), Duration::new(1, 1)); -} - -#[test] -fn checked_add() { - assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); - assert_eq!( - Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), - Some(Duration::new(1, 1)) - ); - assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None); -} - -#[test] -fn saturating_add() { - assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); - assert_eq!( - Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)), - Duration::new(1, 1) - ); - assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); -} - -#[test] -fn sub() { - assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), Duration::new(0, 1)); - assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), Duration::new(0, 999_999_999)); -} - -#[test] -fn checked_sub() { - assert_eq!(Duration::NANOSECOND.checked_sub(Duration::ZERO), Some(Duration::NANOSECOND)); - assert_eq!( - Duration::SECOND.checked_sub(Duration::NANOSECOND), - Some(Duration::new(0, 999_999_999)) - ); - assert_eq!(Duration::ZERO.checked_sub(Duration::NANOSECOND), None); - assert_eq!(Duration::ZERO.checked_sub(Duration::SECOND), None); -} - -#[test] -fn saturating_sub() { - assert_eq!(Duration::NANOSECOND.saturating_sub(Duration::ZERO), Duration::NANOSECOND); - assert_eq!( - Duration::SECOND.saturating_sub(Duration::NANOSECOND), - Duration::new(0, 999_999_999) - ); - assert_eq!(Duration::ZERO.saturating_sub(Duration::NANOSECOND), Duration::ZERO); - assert_eq!(Duration::ZERO.saturating_sub(Duration::SECOND), Duration::ZERO); -} - -#[test] -#[should_panic] -fn sub_bad1() { - let _ = Duration::new(0, 0) - Duration::new(0, 1); -} - -#[test] -#[should_panic] -fn sub_bad2() { - let _ = Duration::new(0, 0) - Duration::new(1, 0); -} - -#[test] -fn mul() { - assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); - assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); - assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); - assert_eq!(Duration::new(0, 500_000_001) * 4000, Duration::new(2000, 4000)); -} - -#[test] -fn checked_mul() { - assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); - assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), Some(Duration::new(2000, 4000))); - assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None); -} - -#[test] -fn saturating_mul() { - assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2)); - assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3)); - assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4)); - assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000)); - assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); -} - -#[test] -fn div() { - assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); - assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); - assert_eq!(Duration::new(1, 1) / 7, Duration::new(0, 142_857_143)); - assert_eq!(Duration::new(99, 999_999_000) / 100, Duration::new(0, 999_999_990)); -} - -#[test] -fn div_duration_f32() { - assert_eq!(Duration::ZERO.div_duration_f32(Duration::MAX), 0.0); - assert_eq!(Duration::MAX.div_duration_f32(Duration::ZERO), f32::INFINITY); - assert_eq!((Duration::SECOND * 2).div_duration_f32(Duration::SECOND), 2.0); - assert!(Duration::ZERO.div_duration_f32(Duration::ZERO).is_nan()); - // These tests demonstrate it doesn't panic with extreme values. - // Accuracy of the computed value is not a huge concern, we know floats don't work well - // at these extremes. - assert!((Duration::MAX).div_duration_f32(Duration::NANOSECOND) > 10.0f32.powf(28.0)); - assert!((Duration::NANOSECOND).div_duration_f32(Duration::MAX) < 0.1); -} - -#[test] -fn div_duration_f64() { - assert_eq!(Duration::ZERO.div_duration_f64(Duration::MAX), 0.0); - assert_eq!(Duration::MAX.div_duration_f64(Duration::ZERO), f64::INFINITY); - assert_eq!((Duration::SECOND * 2).div_duration_f64(Duration::SECOND), 2.0); - assert!(Duration::ZERO.div_duration_f64(Duration::ZERO).is_nan()); - // These tests demonstrate it doesn't panic with extreme values. - // Accuracy of the computed value is not a huge concern, we know floats don't work well - // at these extremes. - assert!((Duration::MAX).div_duration_f64(Duration::NANOSECOND) > 10.0f64.powf(28.0)); - assert!((Duration::NANOSECOND).div_duration_f64(Duration::MAX) < 0.1); -} - -#[test] -fn checked_div() { - assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - assert_eq!(Duration::new(2, 0).checked_div(0), None); -} - -#[test] -fn correct_sum() { - let durations = [ - Duration::new(1, 999_999_999), - Duration::new(2, 999_999_999), - Duration::new(0, 999_999_999), - Duration::new(0, 999_999_999), - Duration::new(0, 999_999_999), - Duration::new(5, 0), - ]; - let sum = durations.iter().sum::(); - assert_eq!(sum, Duration::new(1 + 2 + 5 + 4, 1_000_000_000 - 5)); -} - -#[test] -fn debug_formatting_extreme_values() { - assert_eq!( - format!("{:?}", Duration::new(u64::MAX, 123_456_789)), - "18446744073709551615.123456789s" - ); - assert_eq!(format!("{:.0?}", Duration::MAX), "18446744073709551616s"); - assert_eq!(format!("{:.0?}", Duration::new(u64::MAX, 500_000_000)), "18446744073709551616s"); - assert_eq!(format!("{:.0?}", Duration::new(u64::MAX, 499_999_999)), "18446744073709551615s"); - assert_eq!( - format!("{:.3?}", Duration::new(u64::MAX, 999_500_000)), - "18446744073709551616.000s" - ); - assert_eq!( - format!("{:.3?}", Duration::new(u64::MAX, 999_499_999)), - "18446744073709551615.999s" - ); - assert_eq!( - format!("{:.8?}", Duration::new(u64::MAX, 999_999_995)), - "18446744073709551616.00000000s" - ); - assert_eq!( - format!("{:.8?}", Duration::new(u64::MAX, 999_999_994)), - "18446744073709551615.99999999s" - ); - assert_eq!(format!("{:21.0?}", Duration::MAX), "18446744073709551616s"); - assert_eq!(format!("{:22.0?}", Duration::MAX), "18446744073709551616s "); - assert_eq!(format!("{:24.0?}", Duration::MAX), "18446744073709551616s "); -} - -#[test] -fn debug_formatting_secs() { - assert_eq!(format!("{:?}", Duration::new(7, 000_000_000)), "7s"); - assert_eq!(format!("{:?}", Duration::new(7, 100_000_000)), "7.1s"); - assert_eq!(format!("{:?}", Duration::new(7, 000_010_000)), "7.00001s"); - assert_eq!(format!("{:?}", Duration::new(7, 000_000_001)), "7.000000001s"); - assert_eq!(format!("{:?}", Duration::new(7, 123_456_789)), "7.123456789s"); - - assert_eq!(format!("{:?}", Duration::new(88, 000_000_000)), "88s"); - assert_eq!(format!("{:?}", Duration::new(88, 100_000_000)), "88.1s"); - assert_eq!(format!("{:?}", Duration::new(88, 000_010_000)), "88.00001s"); - assert_eq!(format!("{:?}", Duration::new(88, 000_000_001)), "88.000000001s"); - assert_eq!(format!("{:?}", Duration::new(88, 123_456_789)), "88.123456789s"); - - assert_eq!(format!("{:?}", Duration::new(999, 000_000_000)), "999s"); - assert_eq!(format!("{:?}", Duration::new(999, 100_000_000)), "999.1s"); - assert_eq!(format!("{:?}", Duration::new(999, 000_010_000)), "999.00001s"); - assert_eq!(format!("{:?}", Duration::new(999, 000_000_001)), "999.000000001s"); - assert_eq!(format!("{:?}", Duration::new(999, 123_456_789)), "999.123456789s"); -} - -#[test] -fn debug_formatting_millis() { - assert_eq!(format!("{:?}", Duration::new(0, 7_000_000)), "7ms"); - assert_eq!(format!("{:?}", Duration::new(0, 7_100_000)), "7.1ms"); - assert_eq!(format!("{:?}", Duration::new(0, 7_000_001)), "7.000001ms"); - assert_eq!(format!("{:?}", Duration::new(0, 7_123_456)), "7.123456ms"); - - assert_eq!(format!("{:?}", Duration::new(0, 88_000_000)), "88ms"); - assert_eq!(format!("{:?}", Duration::new(0, 88_100_000)), "88.1ms"); - assert_eq!(format!("{:?}", Duration::new(0, 88_000_001)), "88.000001ms"); - assert_eq!(format!("{:?}", Duration::new(0, 88_123_456)), "88.123456ms"); - - assert_eq!(format!("{:?}", Duration::new(0, 999_000_000)), "999ms"); - assert_eq!(format!("{:?}", Duration::new(0, 999_100_000)), "999.1ms"); - assert_eq!(format!("{:?}", Duration::new(0, 999_000_001)), "999.000001ms"); - assert_eq!(format!("{:?}", Duration::new(0, 999_123_456)), "999.123456ms"); -} - -#[test] -fn debug_formatting_micros() { - assert_eq!(format!("{:?}", Duration::new(0, 7_000)), "7µs"); - assert_eq!(format!("{:?}", Duration::new(0, 7_100)), "7.1µs"); - assert_eq!(format!("{:?}", Duration::new(0, 7_001)), "7.001µs"); - assert_eq!(format!("{:?}", Duration::new(0, 7_123)), "7.123µs"); - - assert_eq!(format!("{:?}", Duration::new(0, 88_000)), "88µs"); - assert_eq!(format!("{:?}", Duration::new(0, 88_100)), "88.1µs"); - assert_eq!(format!("{:?}", Duration::new(0, 88_001)), "88.001µs"); - assert_eq!(format!("{:?}", Duration::new(0, 88_123)), "88.123µs"); - - assert_eq!(format!("{:?}", Duration::new(0, 999_000)), "999µs"); - assert_eq!(format!("{:?}", Duration::new(0, 999_100)), "999.1µs"); - assert_eq!(format!("{:?}", Duration::new(0, 999_001)), "999.001µs"); - assert_eq!(format!("{:?}", Duration::new(0, 999_123)), "999.123µs"); -} - -#[test] -fn debug_formatting_nanos() { - assert_eq!(format!("{:?}", Duration::new(0, 0)), "0ns"); - assert_eq!(format!("{:?}", Duration::new(0, 1)), "1ns"); - assert_eq!(format!("{:?}", Duration::new(0, 88)), "88ns"); - assert_eq!(format!("{:?}", Duration::new(0, 999)), "999ns"); -} - -#[test] -fn debug_formatting_precision_zero() { - assert_eq!(format!("{:.0?}", Duration::new(0, 0)), "0ns"); - assert_eq!(format!("{:.0?}", Duration::new(0, 123)), "123ns"); - - assert_eq!(format!("{:.0?}", Duration::new(0, 1_001)), "1µs"); - assert_eq!(format!("{:.0?}", Duration::new(0, 1_499)), "1µs"); - assert_eq!(format!("{:.0?}", Duration::new(0, 1_500)), "2µs"); - assert_eq!(format!("{:.0?}", Duration::new(0, 1_999)), "2µs"); - - assert_eq!(format!("{:.0?}", Duration::new(0, 1_000_001)), "1ms"); - assert_eq!(format!("{:.0?}", Duration::new(0, 1_499_999)), "1ms"); - assert_eq!(format!("{:.0?}", Duration::new(0, 1_500_000)), "2ms"); - assert_eq!(format!("{:.0?}", Duration::new(0, 1_999_999)), "2ms"); - - assert_eq!(format!("{:.0?}", Duration::new(1, 000_000_001)), "1s"); - assert_eq!(format!("{:.0?}", Duration::new(1, 499_999_999)), "1s"); - assert_eq!(format!("{:.0?}", Duration::new(1, 500_000_000)), "2s"); - assert_eq!(format!("{:.0?}", Duration::new(1, 999_999_999)), "2s"); -} - -#[test] -fn debug_formatting_precision_two() { - assert_eq!(format!("{:.2?}", Duration::new(0, 0)), "0.00ns"); - assert_eq!(format!("{:.2?}", Duration::new(0, 123)), "123.00ns"); - - assert_eq!(format!("{:.2?}", Duration::new(0, 1_000)), "1.00µs"); - assert_eq!(format!("{:.2?}", Duration::new(0, 7_001)), "7.00µs"); - assert_eq!(format!("{:.2?}", Duration::new(0, 7_100)), "7.10µs"); - assert_eq!(format!("{:.2?}", Duration::new(0, 7_109)), "7.11µs"); - assert_eq!(format!("{:.2?}", Duration::new(0, 7_199)), "7.20µs"); - assert_eq!(format!("{:.2?}", Duration::new(0, 1_999)), "2.00µs"); - - assert_eq!(format!("{:.2?}", Duration::new(0, 1_000_000)), "1.00ms"); - assert_eq!(format!("{:.2?}", Duration::new(0, 3_001_000)), "3.00ms"); - assert_eq!(format!("{:.2?}", Duration::new(0, 3_100_000)), "3.10ms"); - assert_eq!(format!("{:.2?}", Duration::new(0, 1_999_999)), "2.00ms"); - - assert_eq!(format!("{:.2?}", Duration::new(1, 000_000_000)), "1.00s"); - assert_eq!(format!("{:.2?}", Duration::new(4, 001_000_000)), "4.00s"); - assert_eq!(format!("{:.2?}", Duration::new(2, 100_000_000)), "2.10s"); - assert_eq!(format!("{:.2?}", Duration::new(2, 104_990_000)), "2.10s"); - assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.11s"); - assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s"); -} - -#[test] -fn debug_formatting_padding() { - assert_eq!("0ns ", format!("{:<9?}", Duration::new(0, 0))); - assert_eq!(" 0ns", format!("{:>9?}", Duration::new(0, 0))); - assert_eq!(" 0ns ", format!("{:^9?}", Duration::new(0, 0))); - assert_eq!("123ns ", format!("{:<9.0?}", Duration::new(0, 123))); - assert_eq!(" 123ns", format!("{:>9.0?}", Duration::new(0, 123))); - assert_eq!(" 123ns ", format!("{:^9.0?}", Duration::new(0, 123))); - assert_eq!("123.0ns ", format!("{:<9.1?}", Duration::new(0, 123))); - assert_eq!(" 123.0ns", format!("{:>9.1?}", Duration::new(0, 123))); - assert_eq!(" 123.0ns ", format!("{:^9.1?}", Duration::new(0, 123))); - assert_eq!("7.1µs ", format!("{:<9?}", Duration::new(0, 7_100))); - assert_eq!(" 7.1µs", format!("{:>9?}", Duration::new(0, 7_100))); - assert_eq!(" 7.1µs ", format!("{:^9?}", Duration::new(0, 7_100))); - assert_eq!("999.123456ms", format!("{:<9?}", Duration::new(0, 999_123_456))); - assert_eq!("999.123456ms", format!("{:>9?}", Duration::new(0, 999_123_456))); - assert_eq!("999.123456ms", format!("{:^9?}", Duration::new(0, 999_123_456))); - assert_eq!("5s ", format!("{:<9?}", Duration::new(5, 0))); - assert_eq!(" 5s", format!("{:>9?}", Duration::new(5, 0))); - assert_eq!(" 5s ", format!("{:^9?}", Duration::new(5, 0))); - assert_eq!("5.000000000000s", format!("{:<9.12?}", Duration::new(5, 0))); - assert_eq!("5.000000000000s", format!("{:>9.12?}", Duration::new(5, 0))); - assert_eq!("5.000000000000s", format!("{:^9.12?}", Duration::new(5, 0))); - - // default alignment is left: - assert_eq!("5s ", format!("{:9?}", Duration::new(5, 0))); -} - -#[test] -fn debug_formatting_precision_high() { - assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs"); - - assert_eq!(format!("{:.9?}", Duration::new(1, 000_000_000)), "1.000000000s"); - assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s"); - assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s"); -} - -#[test] -fn duration_const() { - // test that the methods of `Duration` are usable in a const context - - const DURATION: Duration = Duration::new(0, 123_456_789); - - const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis(); - assert_eq!(SUB_SEC_MILLIS, 123); - - const SUB_SEC_MICROS: u32 = DURATION.subsec_micros(); - assert_eq!(SUB_SEC_MICROS, 123_456); - - const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos(); - assert_eq!(SUB_SEC_NANOS, 123_456_789); - - const IS_ZERO: bool = Duration::ZERO.is_zero(); - assert!(IS_ZERO); - - const SECONDS: u64 = Duration::SECOND.as_secs(); - assert_eq!(SECONDS, 1); - - const FROM_SECONDS: Duration = Duration::from_secs(1); - assert_eq!(FROM_SECONDS, Duration::SECOND); - - const SECONDS_F32: f32 = Duration::SECOND.as_secs_f32(); - assert_eq!(SECONDS_F32, 1.0); - - // FIXME(#110395) - // const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0); - // assert_eq!(FROM_SECONDS_F32, Duration::SECOND); - - const SECONDS_F64: f64 = Duration::SECOND.as_secs_f64(); - assert_eq!(SECONDS_F64, 1.0); - - // FIXME(#110395) - // const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0); - // assert_eq!(FROM_SECONDS_F64, Duration::SECOND); - - const MILLIS: u128 = Duration::SECOND.as_millis(); - assert_eq!(MILLIS, 1_000); - - const FROM_MILLIS: Duration = Duration::from_millis(1_000); - assert_eq!(FROM_MILLIS, Duration::SECOND); - - const MICROS: u128 = Duration::SECOND.as_micros(); - assert_eq!(MICROS, 1_000_000); - - const FROM_MICROS: Duration = Duration::from_micros(1_000_000); - assert_eq!(FROM_MICROS, Duration::SECOND); - - const NANOS: u128 = Duration::SECOND.as_nanos(); - assert_eq!(NANOS, 1_000_000_000); - - const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000); - assert_eq!(FROM_NANOS, Duration::SECOND); - - const MAX: Duration = Duration::new(u64::MAX, 999_999_999); - - const CHECKED_ADD: Option = MAX.checked_add(Duration::SECOND); - assert_eq!(CHECKED_ADD, None); - - const CHECKED_SUB: Option = Duration::ZERO.checked_sub(Duration::SECOND); - assert_eq!(CHECKED_SUB, None); - - const CHECKED_MUL: Option = Duration::SECOND.checked_mul(1); - assert_eq!(CHECKED_MUL, Some(Duration::SECOND)); - - /* FIXME(#110395) - const MUL_F32: Duration = Duration::SECOND.mul_f32(1.0); - assert_eq!(MUL_F32, Duration::SECOND); - - const MUL_F64: Duration = Duration::SECOND.mul_f64(1.0); - assert_eq!(MUL_F64, Duration::SECOND); - - const CHECKED_DIV: Option = Duration::SECOND.checked_div(1); - assert_eq!(CHECKED_DIV, Some(Duration::SECOND)); - - const DIV_F32: Duration = Duration::SECOND.div_f32(1.0); - assert_eq!(DIV_F32, Duration::SECOND); - - const DIV_F64: Duration = Duration::SECOND.div_f64(1.0); - assert_eq!(DIV_F64, Duration::SECOND); - */ - - const DIV_DURATION_F32: f32 = Duration::SECOND.div_duration_f32(Duration::SECOND); - assert_eq!(DIV_DURATION_F32, 1.0); - - const DIV_DURATION_F64: f64 = Duration::SECOND.div_duration_f64(Duration::SECOND); - assert_eq!(DIV_DURATION_F64, 1.0); - - const SATURATING_ADD: Duration = MAX.saturating_add(Duration::SECOND); - assert_eq!(SATURATING_ADD, MAX); - - const SATURATING_SUB: Duration = Duration::ZERO.saturating_sub(Duration::SECOND); - assert_eq!(SATURATING_SUB, Duration::ZERO); - - const SATURATING_MUL: Duration = MAX.saturating_mul(2); - assert_eq!(SATURATING_MUL, MAX); -} - -#[test] -fn from_neg_zero() { - assert_eq!(Duration::try_from_secs_f32(-0.0), Ok(Duration::ZERO)); - assert_eq!(Duration::try_from_secs_f64(-0.0), Ok(Duration::ZERO)); - assert_eq!(Duration::from_secs_f32(-0.0), Duration::ZERO); - assert_eq!(Duration::from_secs_f64(-0.0), Duration::ZERO); -} diff --git a/library/core/tests/tuple.rs b/library/core/tests/tuple.rs deleted file mode 100644 index ea1e281425c..00000000000 --- a/library/core/tests/tuple.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::cmp::Ordering::{Equal, Greater, Less}; - -#[test] -fn test_clone() { - let a = (1, "2"); - let b = a.clone(); - assert_eq!(a, b); -} - -#[test] -fn test_partial_eq() { - let (small, big) = ((1, 2, 3), (3, 2, 1)); - assert_eq!(small, small); - assert_eq!(big, big); - assert_ne!(small, big); - assert_ne!(big, small); -} - -#[test] -fn test_partial_ord() { - let (small, big) = ((1, 2, 3), (3, 2, 1)); - - assert!(small < big); - assert!(!(small < small)); - assert!(!(big < small)); - assert!(!(big < big)); - - assert!(small <= small); - assert!(big <= big); - - assert!(big > small); - assert!(small >= small); - assert!(big >= small); - assert!(big >= big); - - assert!(!((1.0f64, 2.0f64) < (f64::NAN, 3.0))); - assert!(!((1.0f64, 2.0f64) <= (f64::NAN, 3.0))); - assert!(!((1.0f64, 2.0f64) > (f64::NAN, 3.0))); - assert!(!((1.0f64, 2.0f64) >= (f64::NAN, 3.0))); - assert!(((1.0f64, 2.0f64) < (2.0, f64::NAN))); - assert!(!((2.0f64, 2.0f64) < (2.0, f64::NAN))); -} - -#[test] -fn test_ord() { - let (small, big) = ((1, 2, 3), (3, 2, 1)); - assert_eq!(small.cmp(&small), Equal); - assert_eq!(big.cmp(&big), Equal); - assert_eq!(small.cmp(&big), Less); - assert_eq!(big.cmp(&small), Greater); -} - -#[test] -fn test_show() { - let s = format!("{:?}", (1,)); - assert_eq!(s, "(1,)"); - let s = format!("{:?}", (1, true)); - assert_eq!(s, "(1, true)"); - let s = format!("{:?}", (1, "hi", true)); - assert_eq!(s, "(1, \"hi\", true)"); -} diff --git a/library/core/tests/unicode.rs b/library/core/tests/unicode.rs deleted file mode 100644 index bbace0ef66c..00000000000 --- a/library/core/tests/unicode.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[test] -pub fn version() { - let (major, _minor, _update) = core::char::UNICODE_VERSION; - assert!(major >= 10); -} diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs deleted file mode 100644 index 4889b8959ec..00000000000 --- a/library/core/tests/waker.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::ptr; -use std::task::{RawWaker, RawWakerVTable, Waker}; - -#[test] -fn test_waker_getters() { - let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE); - let waker = unsafe { Waker::from_raw(raw_waker) }; - assert_eq!(waker.data() as usize, 42); - assert!(ptr::eq(waker.vtable(), &WAKER_VTABLE)); - - let waker2 = waker.clone(); - assert_eq!(waker2.data() as usize, 43); - assert!(ptr::eq(waker2.vtable(), &WAKER_VTABLE)); -} - -static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( - |data| RawWaker::new(ptr::without_provenance_mut(data as usize + 1), &WAKER_VTABLE), - |_| {}, - |_| {}, - |_| {}, -); - -// https://github.com/rust-lang/rust/issues/102012#issuecomment-1915282956 -mod nop_waker { - use core::future::{Future, ready}; - use core::pin::Pin; - use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; - - const NOP_RAWWAKER: RawWaker = { - fn nop(_: *const ()) {} - const VTAB: RawWakerVTable = RawWakerVTable::new(|_| NOP_RAWWAKER, nop, nop, nop); - RawWaker::new(&() as *const (), &VTAB) - }; - - const NOP_WAKER: &Waker = &unsafe { Waker::from_raw(NOP_RAWWAKER) }; - - const NOP_CONTEXT: Context<'static> = Context::from_waker(NOP_WAKER); - - fn poll_once(f: &mut F) -> Poll - where - F: Future + ?Sized + Unpin, - { - let mut cx = NOP_CONTEXT; - Pin::new(f).as_mut().poll(&mut cx) - } - - #[test] - fn test_const_waker() { - assert_eq!(poll_once(&mut ready(1)), Poll::Ready(1)); - } -} diff --git a/library/coretests/Cargo.toml b/library/coretests/Cargo.toml new file mode 100644 index 00000000000..ec940abea11 --- /dev/null +++ b/library/coretests/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "coretests" +version = "0.0.0" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rust.git" +description = "Tests for the Rust Core Library" +autotests = false +autobenches = false +edition = "2021" + +[lib] +path = "lib.rs" +test = false +bench = false + +[[test]] +name = "coretests" +path = "tests/lib.rs" + +[[bench]] +name = "corebenches" +path = "benches/lib.rs" +test = true + +[dev-dependencies] +rand = { version = "0.8.5", default-features = false } +rand_xorshift = { version = "0.3.0", default-features = false } diff --git a/library/coretests/benches/any.rs b/library/coretests/benches/any.rs new file mode 100644 index 00000000000..6b150432f87 --- /dev/null +++ b/library/coretests/benches/any.rs @@ -0,0 +1,13 @@ +use core::any::*; + +use test::{Bencher, black_box}; + +#[bench] +fn bench_downcast_ref(b: &mut Bencher) { + b.iter(|| { + let mut x = 0; + let mut y = &mut x as &mut dyn Any; + black_box(&mut y); + black_box(y.downcast_ref::() == Some(&0)); + }); +} diff --git a/library/coretests/benches/array.rs b/library/coretests/benches/array.rs new file mode 100644 index 00000000000..751f3235a5f --- /dev/null +++ b/library/coretests/benches/array.rs @@ -0,0 +1,18 @@ +use test::{Bencher, black_box}; + +macro_rules! map_array { + ($func_name:ident, $start_item: expr, $map_item: expr, $arr_size: expr) => { + #[bench] + fn $func_name(b: &mut Bencher) { + let arr = [$start_item; $arr_size]; + b.iter(|| black_box(arr).map(|_| black_box($map_item))); + } + }; +} + +map_array!(map_8byte_8byte_8, 0u64, 1u64, 80); +map_array!(map_8byte_8byte_64, 0u64, 1u64, 640); +map_array!(map_8byte_8byte_256, 0u64, 1u64, 2560); + +map_array!(map_8byte_256byte_256, 0u64, [0u64; 4], 2560); +map_array!(map_256byte_8byte_256, [0u64; 4], 0u64, 2560); diff --git a/library/coretests/benches/ascii.rs b/library/coretests/benches/ascii.rs new file mode 100644 index 00000000000..3fe45aa360b --- /dev/null +++ b/library/coretests/benches/ascii.rs @@ -0,0 +1,381 @@ +mod is_ascii; + +// Lower-case ASCII 'a' is the first byte that has its highest bit set +// after wrap-adding 0x1F: +// +// b'a' + 0x1F == 0x80 == 0b1000_0000 +// b'z' + 0x1F == 0x98 == 0b1001_1000 +// +// Lower-case ASCII 'z' is the last byte that has its highest bit unset +// after wrap-adding 0x05: +// +// b'a' + 0x05 == 0x66 == 0b0110_0110 +// b'z' + 0x05 == 0x7F == 0b0111_1111 +// +// … except for 0xFB to 0xFF, but those are in the range of bytes +// that have the highest bit unset again after adding 0x1F. +// +// So `(byte + 0x1f) & !(byte + 5)` has its highest bit set +// iff `byte` is a lower-case ASCII letter. +// +// Lower-case ASCII letters all have the 0x20 bit set. +// (Two positions right of 0x80, the highest bit.) +// Unsetting that bit produces the same letter, in upper-case. +// +// Therefore: +fn branchless_to_ascii_upper_case(byte: u8) -> u8 { + byte & !((byte.wrapping_add(0x1f) & !byte.wrapping_add(0x05) & 0x80) >> 2) +} + +macro_rules! benches { + ($( fn $name: ident($arg: ident: &mut [u8]) $body: block )+ @iter $( $is_: ident, )+) => { + benches! {@ + $( fn $name($arg: &mut [u8]) $body )+ + $( fn $is_(bytes: &mut [u8]) { bytes.iter().all(u8::$is_) } )+ + } + }; + + (@$( fn $name: ident($arg: ident: &mut [u8]) $body: block )+) => { + benches!(mod short SHORT $($name $arg $body)+); + benches!(mod medium MEDIUM $($name $arg $body)+); + benches!(mod long LONG $($name $arg $body)+); + }; + + (mod $mod_name: ident $input: ident $($name: ident $arg: ident $body: block)+) => { + mod $mod_name { + use super::*; + + $( + #[bench] + fn $name(bencher: &mut Bencher) { + bencher.bytes = $input.len() as u64; + bencher.iter(|| { + let mut vec = $input.as_bytes().to_vec(); + { + let $arg = &mut vec[..]; + black_box($body); + } + vec + }) + } + )+ + } + } +} + +use std::fmt::Write; + +use test::{Bencher, black_box}; + +const ASCII_CASE_MASK: u8 = 0b0010_0000; + +benches! { + fn case00_alloc_only(_bytes: &mut [u8]) {} + + fn case01_black_box_read_each_byte(bytes: &mut [u8]) { + for byte in bytes { + black_box(*byte); + } + } + + fn case02_lookup_table(bytes: &mut [u8]) { + for byte in bytes { + *byte = ASCII_UPPERCASE_MAP[*byte as usize] + } + } + + fn case03_branch_and_subtract(bytes: &mut [u8]) { + for byte in bytes { + *byte = if b'a' <= *byte && *byte <= b'z' { + *byte - b'a' + b'A' + } else { + *byte + } + } + } + + fn case04_branch_and_mask(bytes: &mut [u8]) { + for byte in bytes { + *byte = if b'a' <= *byte && *byte <= b'z' { + *byte & !0x20 + } else { + *byte + } + } + } + + fn case05_branchless(bytes: &mut [u8]) { + for byte in bytes { + *byte = branchless_to_ascii_upper_case(*byte) + } + } + + fn case06_libcore(bytes: &mut [u8]) { + bytes.make_ascii_uppercase() + } + + fn case07_fake_simd_u32(bytes: &mut [u8]) { + // SAFETY: transmuting a sequence of `u8` to `u32` is always fine + let (before, aligned, after) = unsafe { + bytes.align_to_mut::() + }; + for byte in before { + *byte = branchless_to_ascii_upper_case(*byte) + } + for word in aligned { + // FIXME: this is incorrect for some byte values: + // addition within a byte can carry/overflow into the next byte. + // Test case: b"\xFFz " + *word &= !( + ( + word.wrapping_add(0x1f1f1f1f) & + !word.wrapping_add(0x05050505) & + 0x80808080 + ) >> 2 + ) + } + for byte in after { + *byte = branchless_to_ascii_upper_case(*byte) + } + } + + fn case08_fake_simd_u64(bytes: &mut [u8]) { + // SAFETY: transmuting a sequence of `u8` to `u64` is always fine + let (before, aligned, after) = unsafe { + bytes.align_to_mut::() + }; + for byte in before { + *byte = branchless_to_ascii_upper_case(*byte) + } + for word in aligned { + // FIXME: like above, this is incorrect for some byte values. + *word &= !( + ( + word.wrapping_add(0x1f1f1f1f_1f1f1f1f) & + !word.wrapping_add(0x05050505_05050505) & + 0x80808080_80808080 + ) >> 2 + ) + } + for byte in after { + *byte = branchless_to_ascii_upper_case(*byte) + } + } + + fn case09_mask_mult_bool_branchy_lookup_table(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + if b >= 0x80 { return false } + match ASCII_CHARACTER_CLASS[b as usize] { + L | Lx => true, + _ => false, + } + } + for byte in bytes { + *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) + } + } + + fn case10_mask_mult_bool_lookup_table(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match ASCII_CHARACTER_CLASS[b as usize] { + L | Lx => true, + _ => false + } + } + for byte in bytes { + *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) + } + } + + fn case11_mask_mult_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'..=b'z' => true, + _ => false + } + } + for byte in bytes { + *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8)) + } + } + + fn case12_mask_shifted_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'..=b'z' => true, + _ => false + } + } + for byte in bytes { + *byte &= !((is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK) + } + } + + fn case13_subtract_shifted_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'..=b'z' => true, + _ => false + } + } + for byte in bytes { + *byte -= (is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK + } + } + + fn case14_subtract_multiplied_bool_match_range(bytes: &mut [u8]) { + fn is_ascii_lowercase(b: u8) -> bool { + match b { + b'a'..=b'z' => true, + _ => false + } + } + for byte in bytes { + *byte -= (b'a' - b'A') * is_ascii_lowercase(*byte) as u8 + } + } + + @iter + + is_ascii, + is_ascii_alphabetic, + is_ascii_uppercase, + is_ascii_lowercase, + is_ascii_alphanumeric, + is_ascii_digit, + is_ascii_hexdigit, + is_ascii_punctuation, + is_ascii_graphic, + is_ascii_whitespace, + is_ascii_control, +} + +macro_rules! repeat { + ($s: expr) => { + concat!($s, $s, $s, $s, $s, $s, $s, $s, $s, $s) + }; +} + +const SHORT: &str = "Alice's"; +const MEDIUM: &str = "Alice's Adventures in Wonderland"; +const LONG: &str = repeat!( + r#" + La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850) + Alice's Adventures in Wonderland (1865) + Phantasmagoria and Other Poems (1869) + Through the Looking-Glass, and What Alice Found There + (includes "Jabberwocky" and "The Walrus and the Carpenter") (1871) + The Hunting of the Snark (1876) + Rhyme? And Reason? (1883) – shares some contents with the 1869 collection, + including the long poem "Phantasmagoria" + A Tangled Tale (1885) + Sylvie and Bruno (1889) + Sylvie and Bruno Concluded (1893) + Pillow Problems (1893) + What the Tortoise Said to Achilles (1895) + Three Sunsets and Other Poems (1898) + The Manlet (1903)[106] +"# +); + +#[rustfmt::skip] +const ASCII_UPPERCASE_MAP: [u8; 256] = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'', + b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', + b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', + b'8', b'9', b':', b';', b'<', b'=', b'>', b'?', + b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G', + b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', + b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_', + b'`', + + b'A', b'B', b'C', b'D', b'E', b'F', b'G', + b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', + b'X', b'Y', b'Z', + + b'{', b'|', b'}', b'~', 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +]; + +enum AsciiCharacterClass { + C, // control + Cw, // control whitespace + W, // whitespace + D, // digit + L, // lowercase + Lx, // lowercase hex digit + U, // uppercase + Ux, // uppercase hex digit + P, // punctuation + N, // Non-ASCII +} +use self::AsciiCharacterClass::*; + +#[rustfmt::skip] +static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ +// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f + C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_ + C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_ + W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_ + D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_ + P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_ + U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_ + P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_ + L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_ + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, + N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, +]; + +const ASCII_PATH: &[u8] = b"home/kyubey/rust/build/x86_64-unknown-linux-gnu/stage0/lib:/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-tools/release/deps"; +const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; + +#[bench] +fn bench_ascii_escape_display_no_escape(b: &mut Bencher) { + let mut writer = String::with_capacity(8 * 1024); + + b.iter(move || { + writer.clear(); + let iter = ASCII_PATH.escape_ascii(); + write!(writer, "{}", iter).unwrap(); + writer.len() + }) +} + +#[bench] +fn bench_ascii_escape_display_mixed(b: &mut Bencher) { + let mut writer = String::with_capacity(8 * 1024); + + b.iter(move || { + writer.clear(); + let iter = RUST_INCANTATION.escape_ascii(); + write!(writer, "{}", iter).unwrap(); + writer.len() + }) +} diff --git a/library/coretests/benches/ascii/is_ascii.rs b/library/coretests/benches/ascii/is_ascii.rs new file mode 100644 index 00000000000..ced7084fb0e --- /dev/null +++ b/library/coretests/benches/ascii/is_ascii.rs @@ -0,0 +1,123 @@ +use test::{Bencher, black_box}; + +use super::{LONG, MEDIUM, SHORT}; + +macro_rules! benches { + ($( fn $name: ident($arg: ident: &[u8]) $body: block )+) => { + benches!(mod short SHORT[..] $($name $arg $body)+); + benches!(mod medium MEDIUM[..] $($name $arg $body)+); + benches!(mod long LONG[..] $($name $arg $body)+); + // Ensure we benchmark cases where the functions are called with strings + // that are not perfectly aligned or have a length which is not a + // multiple of size_of::() (or both) + benches!(mod unaligned_head_medium MEDIUM[1..] $($name $arg $body)+); + benches!(mod unaligned_tail_medium MEDIUM[..(MEDIUM.len() - 1)] $($name $arg $body)+); + benches!(mod unaligned_both_medium MEDIUM[1..(MEDIUM.len() - 1)] $($name $arg $body)+); + benches!(mod unaligned_head_long LONG[1..] $($name $arg $body)+); + benches!(mod unaligned_tail_long LONG[..(LONG.len() - 1)] $($name $arg $body)+); + benches!(mod unaligned_both_long LONG[1..(LONG.len() - 1)] $($name $arg $body)+); + }; + + (mod $mod_name: ident $input: ident [$range: expr] $($name: ident $arg: ident $body: block)+) => { + mod $mod_name { + use super::*; + $( + #[bench] + fn $name(bencher: &mut Bencher) { + bencher.bytes = $input[$range].len() as u64; + let mut vec = $input.as_bytes().to_vec(); + bencher.iter(|| { + let $arg: &[u8] = &black_box(&mut vec)[$range]; + black_box($body) + }) + } + )+ + } + }; +} + +benches! { + fn case00_libcore(bytes: &[u8]) { + bytes.is_ascii() + } + + fn case01_iter_all(bytes: &[u8]) { + bytes.iter().all(|b| b.is_ascii()) + } + + fn case02_align_to(bytes: &[u8]) { + is_ascii_align_to(bytes) + } + + fn case03_align_to_unrolled(bytes: &[u8]) { + is_ascii_align_to_unrolled(bytes) + } + + fn case04_while_loop(bytes: &[u8]) { + // Process chunks of 32 bytes at a time in the fast path to enable + // auto-vectorization and use of `pmovmskb`. Two 128-bit vector registers + // can be OR'd together and then the resulting vector can be tested for + // non-ASCII bytes. + const CHUNK_SIZE: usize = 32; + + let mut i = 0; + + while i + CHUNK_SIZE <= bytes.len() { + let chunk_end = i + CHUNK_SIZE; + + // Get LLVM to produce a `pmovmskb` instruction on x86-64 which + // creates a mask from the most significant bit of each byte. + // ASCII bytes are less than 128 (0x80), so their most significant + // bit is unset. + let mut count = 0; + while i < chunk_end { + count += bytes[i].is_ascii() as u8; + i += 1; + } + + // All bytes should be <= 127 so count is equal to chunk size. + if count != CHUNK_SIZE as u8 { + return false; + } + } + + // Process the remaining `bytes.len() % N` bytes. + let mut is_ascii = true; + while i < bytes.len() { + is_ascii &= bytes[i].is_ascii(); + i += 1; + } + + is_ascii + } +} + +// These are separate since it's easier to debug errors if they don't go through +// macro expansion first. +fn is_ascii_align_to(bytes: &[u8]) -> bool { + if bytes.len() < core::mem::size_of::() { + return bytes.iter().all(|b| b.is_ascii()); + } + // SAFETY: transmuting a sequence of `u8` to `usize` is always fine + let (head, body, tail) = unsafe { bytes.align_to::() }; + head.iter().all(|b| b.is_ascii()) + && body.iter().all(|w| !contains_nonascii(*w)) + && tail.iter().all(|b| b.is_ascii()) +} + +fn is_ascii_align_to_unrolled(bytes: &[u8]) -> bool { + if bytes.len() < core::mem::size_of::() { + return bytes.iter().all(|b| b.is_ascii()); + } + // SAFETY: transmuting a sequence of `u8` to `[usize; 2]` is always fine + let (head, body, tail) = unsafe { bytes.align_to::<[usize; 2]>() }; + head.iter().all(|b| b.is_ascii()) + && body.iter().all(|w| !contains_nonascii(w[0] | w[1])) + && tail.iter().all(|b| b.is_ascii()) +} + +#[inline] +fn contains_nonascii(v: usize) -> bool { + const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; core::mem::size_of::()]); + (NONASCII_MASK & v) != 0 +} diff --git a/library/coretests/benches/char/methods.rs b/library/coretests/benches/char/methods.rs new file mode 100644 index 00000000000..ed71920a4fc --- /dev/null +++ b/library/coretests/benches/char/methods.rs @@ -0,0 +1,89 @@ +use test::{Bencher, black_box}; + +const CHARS: [char; 9] = ['0', 'x', '2', '5', 'A', 'f', '7', '8', '9']; +const RADIX: [u32; 5] = [2, 8, 10, 16, 32]; + +#[bench] +fn bench_to_digit_radix_2(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(2)).min()) +} + +#[bench] +fn bench_to_digit_radix_10(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(10)).min()) +} + +#[bench] +fn bench_to_digit_radix_16(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(16)).min()) +} + +#[bench] +fn bench_to_digit_radix_36(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_digit(36)).min()) +} + +#[bench] +fn bench_to_digit_radix_var(b: &mut Bencher) { + b.iter(|| { + CHARS + .iter() + .cycle() + .zip(RADIX.iter().cycle()) + .take(10_000) + .map(|(c, radix)| black_box(c).to_digit(*radix)) + .min() + }) +} + +#[bench] +fn bench_to_ascii_uppercase(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_ascii_uppercase()).min()) +} + +#[bench] +fn bench_to_ascii_lowercase(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| black_box(c).to_ascii_lowercase()).min()) +} + +#[bench] +fn bench_ascii_mix_to_uppercase(b: &mut Bencher) { + b.iter(|| { + (0..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_uppercase()).count() + }) +} + +#[bench] +fn bench_ascii_mix_to_lowercase(b: &mut Bencher) { + b.iter(|| { + (0..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_lowercase()).count() + }) +} + +#[bench] +fn bench_ascii_char_to_uppercase(b: &mut Bencher) { + b.iter(|| { + (0..=127).cycle().take(10_000).map(|b| black_box(char::from(b)).to_uppercase()).count() + }) +} + +#[bench] +fn bench_ascii_char_to_lowercase(b: &mut Bencher) { + b.iter(|| { + (0..=127).cycle().take(10_000).map(|b| black_box(char::from(b)).to_lowercase()).count() + }) +} + +#[bench] +fn bench_non_ascii_char_to_uppercase(b: &mut Bencher) { + b.iter(|| { + (128..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_uppercase()).count() + }) +} + +#[bench] +fn bench_non_ascii_char_to_lowercase(b: &mut Bencher) { + b.iter(|| { + (128..=255).cycle().take(10_000).map(|b| black_box(char::from(b)).to_lowercase()).count() + }) +} diff --git a/library/coretests/benches/char/mod.rs b/library/coretests/benches/char/mod.rs new file mode 100644 index 00000000000..9ca51a76847 --- /dev/null +++ b/library/coretests/benches/char/mod.rs @@ -0,0 +1 @@ +mod methods; diff --git a/library/coretests/benches/fmt.rs b/library/coretests/benches/fmt.rs new file mode 100644 index 00000000000..ed478b0f1e0 --- /dev/null +++ b/library/coretests/benches/fmt.rs @@ -0,0 +1,165 @@ +use std::fmt::{self, Write as FmtWrite}; +use std::io::{self, Write as IoWrite}; + +use test::{Bencher, black_box}; + +#[bench] +fn write_vec_value(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + for _ in 0..1000 { + mem.write_all(black_box("abc").as_bytes()).unwrap(); + } + }); +} + +#[bench] +fn write_vec_ref(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + wr.write_all(black_box("abc").as_bytes()).unwrap(); + } + }); +} + +#[bench] +fn write_vec_macro1(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + write!(wr, "{}", black_box("abc")).unwrap(); + } + }); +} + +#[bench] +fn write_vec_macro2(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + write!(wr, "{}", black_box("abc")).unwrap(); + } + }); +} + +#[bench] +fn write_vec_macro_debug(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + write!(wr, "{:?}", black_box("☃")).unwrap(); + } + }); +} + +#[bench] +fn write_str_value(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + for _ in 0..1000 { + mem.write_str(black_box("abc")).unwrap(); + } + }); +} + +#[bench] +fn write_str_ref(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + wr.write_str(black_box("abc")).unwrap(); + } + }); +} + +#[bench] +fn write_str_macro1(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + for _ in 0..1000 { + write!(mem, "{}", black_box("abc")).unwrap(); + } + }); +} + +#[bench] +fn write_str_macro2(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + write!(wr, "{}", black_box("abc")).unwrap(); + } + }); +} + +#[bench] +fn write_str_macro_debug(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + write!(wr, "{:?}", black_box("☃")).unwrap(); + } + }); +} + +#[bench] +fn write_str_macro_debug_ascii(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + write!(wr, "{:?}", black_box("Hello, World!")).unwrap(); + } + }); +} + +#[bench] +fn write_u128_max(bh: &mut Bencher) { + bh.iter(|| { + test::black_box(format!("{}", u128::MAX)); + }); +} + +#[bench] +fn write_u128_min(bh: &mut Bencher) { + bh.iter(|| { + let s = format!("{}", 0u128); + test::black_box(s); + }); +} + +#[bench] +fn write_u64_max(bh: &mut Bencher) { + bh.iter(|| { + test::black_box(format!("{}", u64::MAX)); + }); +} + +#[bench] +fn write_u64_min(bh: &mut Bencher) { + bh.iter(|| { + test::black_box(format!("{}", 0u64)); + }); +} + +#[bench] +fn write_u8_max(bh: &mut Bencher) { + bh.iter(|| { + test::black_box(format!("{}", u8::MAX)); + }); +} + +#[bench] +fn write_u8_min(bh: &mut Bencher) { + bh.iter(|| { + test::black_box(format!("{}", 0u8)); + }); +} diff --git a/library/coretests/benches/hash/mod.rs b/library/coretests/benches/hash/mod.rs new file mode 100644 index 00000000000..4f2e152b695 --- /dev/null +++ b/library/coretests/benches/hash/mod.rs @@ -0,0 +1 @@ +mod sip; diff --git a/library/coretests/benches/hash/sip.rs b/library/coretests/benches/hash/sip.rs new file mode 100644 index 00000000000..c6562d3c011 --- /dev/null +++ b/library/coretests/benches/hash/sip.rs @@ -0,0 +1,124 @@ +#![allow(deprecated)] + +use core::hash::*; + +use test::{Bencher, black_box}; + +fn hash_bytes(mut s: H, x: &[u8]) -> u64 { + Hasher::write(&mut s, x); + s.finish() +} + +fn hash_with(mut st: H, x: &T) -> u64 { + x.hash(&mut st); + st.finish() +} + +fn hash(x: &T) -> u64 { + hash_with(SipHasher::new(), x) +} + +#[bench] +fn bench_str_under_8_bytes(b: &mut Bencher) { + let s = "foo"; + b.iter(|| { + assert_eq!(hash(&s), 16262950014981195938); + }) +} + +#[bench] +fn bench_str_of_8_bytes(b: &mut Bencher) { + let s = "foobar78"; + b.iter(|| { + assert_eq!(hash(&s), 4898293253460910787); + }) +} + +#[bench] +fn bench_str_over_8_bytes(b: &mut Bencher) { + let s = "foobarbaz0"; + b.iter(|| { + assert_eq!(hash(&s), 10581415515220175264); + }) +} + +#[bench] +fn bench_long_str(b: &mut Bencher) { + let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \ + incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \ + exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \ + irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \ + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \ + officia deserunt mollit anim id est laborum."; + b.iter(|| { + assert_eq!(hash(&s), 17717065544121360093); + }) +} + +#[bench] +fn bench_u32(b: &mut Bencher) { + let u = 162629500u32; + let u = black_box(u); + b.iter(|| hash(&u)); + b.bytes = 8; +} + +#[bench] +fn bench_u32_keyed(b: &mut Bencher) { + let u = 162629500u32; + let u = black_box(u); + let k1 = black_box(0x1); + let k2 = black_box(0x2); + b.iter(|| hash_with(SipHasher::new_with_keys(k1, k2), &u)); + b.bytes = 8; +} + +#[bench] +fn bench_u64(b: &mut Bencher) { + let u = 16262950014981195938u64; + let u = black_box(u); + b.iter(|| hash(&u)); + b.bytes = 8; +} + +#[bench] +fn bench_bytes_4(b: &mut Bencher) { + let data = black_box([b' '; 4]); + b.iter(|| hash_bytes(SipHasher::default(), &data)); + b.bytes = 4; +} + +#[bench] +fn bench_bytes_7(b: &mut Bencher) { + let data = black_box([b' '; 7]); + b.iter(|| hash_bytes(SipHasher::default(), &data)); + b.bytes = 7; +} + +#[bench] +fn bench_bytes_8(b: &mut Bencher) { + let data = black_box([b' '; 8]); + b.iter(|| hash_bytes(SipHasher::default(), &data)); + b.bytes = 8; +} + +#[bench] +fn bench_bytes_a_16(b: &mut Bencher) { + let data = black_box([b' '; 16]); + b.iter(|| hash_bytes(SipHasher::default(), &data)); + b.bytes = 16; +} + +#[bench] +fn bench_bytes_b_32(b: &mut Bencher) { + let data = black_box([b' '; 32]); + b.iter(|| hash_bytes(SipHasher::default(), &data)); + b.bytes = 32; +} + +#[bench] +fn bench_bytes_c_128(b: &mut Bencher) { + let data = black_box([b' '; 128]); + b.iter(|| hash_bytes(SipHasher::default(), &data)); + b.bytes = 128; +} diff --git a/library/coretests/benches/iter.rs b/library/coretests/benches/iter.rs new file mode 100644 index 00000000000..e14f26b7290 --- /dev/null +++ b/library/coretests/benches/iter.rs @@ -0,0 +1,548 @@ +use core::borrow::Borrow; +use core::iter::*; +use core::mem; +use core::num::Wrapping; +use core::ops::Range; + +use test::{Bencher, black_box}; + +#[bench] +fn bench_rposition(b: &mut Bencher) { + let it: Vec = (0..300).collect(); + b.iter(|| { + it.iter().rposition(|&x| x <= 150); + }); +} + +#[bench] +fn bench_skip_while(b: &mut Bencher) { + b.iter(|| { + let it = 0..100; + let mut sum = 0; + it.skip_while(|&x| { + sum += x; + sum < 4000 + }) + .all(|_| true); + }); +} + +#[bench] +fn bench_multiple_take(b: &mut Bencher) { + let mut it = (0..42).cycle(); + b.iter(|| { + let n = it.next().unwrap(); + for _ in 0..n { + it.clone().take(it.next().unwrap()).all(|_| true); + } + }); +} + +fn scatter(x: i32) -> i32 { + (x * 31) % 127 +} + +#[bench] +fn bench_max_by_key(b: &mut Bencher) { + b.iter(|| { + let it = 0..100; + it.map(black_box).max_by_key(|&x| scatter(x)) + }) +} + +// https://www.reddit.com/r/rust/comments/31syce/using_iterators_to_find_the_index_of_the_min_or/ +#[bench] +fn bench_max_by_key2(b: &mut Bencher) { + fn max_index_iter(array: &[i32]) -> usize { + array.iter().enumerate().max_by_key(|&(_, item)| item).unwrap().0 + } + + let mut data = vec![0; 1638]; + data[514] = 9999; + + b.iter(|| max_index_iter(&data)); +} + +#[bench] +fn bench_max(b: &mut Bencher) { + b.iter(|| { + let it = 0..100; + it.map(black_box).map(scatter).max() + }) +} + +#[bench] +fn bench_range_step_by_sum_reducible(b: &mut Bencher) { + let r = 0u32..1024; + b.iter(|| { + let r = black_box(r.clone()).step_by(8); + + let mut sum: u32 = 0; + for i in r { + sum += i; + } + + sum + }) +} + +#[bench] +fn bench_range_step_by_loop_u32(b: &mut Bencher) { + let r = 0..(u16::MAX as u32); + b.iter(|| { + let r = black_box(r.clone()).step_by(64); + + let mut sum: u32 = 0; + for i in r { + let i = i ^ i.wrapping_sub(1); + sum = sum.wrapping_add(i); + } + + sum + }) +} + +#[bench] +fn bench_range_step_by_fold_usize(b: &mut Bencher) { + let r: Range = 0..(u16::MAX as usize); + b.iter(|| { + let r = black_box(r.clone()); + r.step_by(64) + .map(|x: usize| x ^ (x.wrapping_sub(1))) + .fold(0usize, |acc, i| acc.wrapping_add(i)) + }) +} + +#[bench] +fn bench_range_step_by_fold_u16(b: &mut Bencher) { + let r: Range = 0..u16::MAX; + b.iter(|| { + let r = black_box(r.clone()); + r.step_by(64).map(|x: u16| x ^ (x.wrapping_sub(1))).fold(0u16, |acc, i| acc.wrapping_add(i)) + }) +} + +pub fn copy_zip(xs: &[u8], ys: &mut [u8]) { + for (a, b) in ys.iter_mut().zip(xs) { + *a = *b; + } +} + +pub fn add_zip(xs: &[f32], ys: &mut [f32]) { + for (a, b) in ys.iter_mut().zip(xs) { + *a += *b; + } +} + +#[bench] +fn bench_zip_copy(b: &mut Bencher) { + let source = vec![0u8; 16 * 1024]; + let mut dst = black_box(vec![0u8; 16 * 1024]); + b.iter(|| copy_zip(&source, &mut dst)) +} + +#[bench] +fn bench_zip_add(b: &mut Bencher) { + let source = vec![1.; 16 * 1024]; + let mut dst = vec![0.; 16 * 1024]; + b.iter(|| add_zip(&source, &mut dst)); +} + +/// `Iterator::for_each` implemented as a plain loop. +fn for_each_loop(iter: I, mut f: F) +where + I: Iterator, + F: FnMut(I::Item), +{ + for item in iter { + f(item); + } +} + +/// `Iterator::for_each` implemented with `fold` for internal iteration. +/// (except when `by_ref()` effectively disables that optimization.) +fn for_each_fold(iter: I, mut f: F) +where + I: Iterator, + F: FnMut(I::Item), +{ + iter.fold((), move |(), item| f(item)); +} + +#[bench] +fn bench_for_each_chain_loop(b: &mut Bencher) { + b.iter(|| { + let mut acc = 0; + let iter = (0i64..1000000).chain(0..1000000).map(black_box); + for_each_loop(iter, |x| acc += x); + acc + }); +} + +#[bench] +fn bench_for_each_chain_fold(b: &mut Bencher) { + b.iter(|| { + let mut acc = 0; + let iter = (0i64..1000000).chain(0..1000000).map(black_box); + for_each_fold(iter, |x| acc += x); + acc + }); +} + +#[bench] +fn bench_for_each_chain_ref_fold(b: &mut Bencher) { + b.iter(|| { + let mut acc = 0; + let mut iter = (0i64..1000000).chain(0..1000000).map(black_box); + for_each_fold(iter.by_ref(), |x| acc += x); + acc + }); +} + +/// Helper to benchmark `sum` for iterators taken by value which +/// can optimize `fold`, and by reference which cannot. +macro_rules! bench_sums { + ($bench_sum:ident, $bench_ref_sum:ident, $iter:expr) => { + #[bench] + fn $bench_sum(b: &mut Bencher) { + b.iter(|| -> i64 { $iter.map(black_box).sum() }); + } + + #[bench] + fn $bench_ref_sum(b: &mut Bencher) { + b.iter(|| -> i64 { $iter.map(black_box).by_ref().sum() }); + } + }; +} + +bench_sums! { + bench_flat_map_sum, + bench_flat_map_ref_sum, + (0i64..1000).flat_map(|x| x..x+1000) +} + +bench_sums! { + bench_flat_map_chain_sum, + bench_flat_map_chain_ref_sum, + (0i64..1000000).flat_map(|x| once(x).chain(once(x))) +} + +bench_sums! { + bench_enumerate_sum, + bench_enumerate_ref_sum, + (0i64..1000000).enumerate().map(|(i, x)| x * i as i64) +} + +bench_sums! { + bench_enumerate_chain_sum, + bench_enumerate_chain_ref_sum, + (0i64..1000000).chain(0..1000000).enumerate().map(|(i, x)| x * i as i64) +} + +bench_sums! { + bench_filter_sum, + bench_filter_ref_sum, + (0i64..1000000).filter(|x| x % 3 == 0) +} + +bench_sums! { + bench_filter_chain_sum, + bench_filter_chain_ref_sum, + (0i64..1000000).chain(0..1000000).filter(|x| x % 3 == 0) +} + +bench_sums! { + bench_filter_map_sum, + bench_filter_map_ref_sum, + (0i64..1000000).filter_map(|x| x.checked_mul(x)) +} + +bench_sums! { + bench_filter_map_chain_sum, + bench_filter_map_chain_ref_sum, + (0i64..1000000).chain(0..1000000).filter_map(|x| x.checked_mul(x)) +} + +bench_sums! { + bench_fuse_sum, + bench_fuse_ref_sum, + (0i64..1000000).fuse() +} + +bench_sums! { + bench_fuse_chain_sum, + bench_fuse_chain_ref_sum, + (0i64..1000000).chain(0..1000000).fuse() +} + +bench_sums! { + bench_inspect_sum, + bench_inspect_ref_sum, + (0i64..1000000).inspect(|_| {}) +} + +bench_sums! { + bench_inspect_chain_sum, + bench_inspect_chain_ref_sum, + (0i64..1000000).chain(0..1000000).inspect(|_| {}) +} + +bench_sums! { + bench_peekable_sum, + bench_peekable_ref_sum, + (0i64..1000000).peekable() +} + +bench_sums! { + bench_peekable_chain_sum, + bench_peekable_chain_ref_sum, + (0i64..1000000).chain(0..1000000).peekable() +} + +bench_sums! { + bench_skip_sum, + bench_skip_ref_sum, + (0i64..1000000).skip(1000) +} + +bench_sums! { + bench_skip_chain_sum, + bench_skip_chain_ref_sum, + (0i64..1000000).chain(0..1000000).skip(1000) +} + +bench_sums! { + bench_skip_while_sum, + bench_skip_while_ref_sum, + (0i64..1000000).skip_while(|&x| x < 1000) +} + +bench_sums! { + bench_skip_while_chain_sum, + bench_skip_while_chain_ref_sum, + (0i64..1000000).chain(0..1000000).skip_while(|&x| x < 1000) +} + +bench_sums! { + bench_take_while_chain_sum, + bench_take_while_chain_ref_sum, + (0i64..1000000).chain(1000000..).take_while(|&x| x < 1111111) +} + +bench_sums! { + bench_cycle_take_sum, + bench_cycle_take_ref_sum, + (0..10000).cycle().take(1000000) +} + +bench_sums! { + bench_cycle_skip_take_sum, + bench_cycle_skip_take_ref_sum, + (0..100000).cycle().skip(1000000).take(1000000) +} + +bench_sums! { + bench_cycle_take_skip_sum, + bench_cycle_take_skip_ref_sum, + (0..100000).cycle().take(1000000).skip(100000) +} + +bench_sums! { + bench_skip_cycle_skip_zip_add_sum, + bench_skip_cycle_skip_zip_add_ref_sum, + (0..100000).skip(100).cycle().skip(100) + .zip((0..100000).cycle().skip(10)) + .map(|(a,b)| a+b) + .skip(100000) + .take(1000000) +} + +// Checks whether Skip> is as fast as Zip, Skip>, from +// https://users.rust-lang.org/t/performance-difference-between-iterator-zip-and-skip-order/15743 +#[bench] +fn bench_zip_then_skip(b: &mut Bencher) { + let v: Vec<_> = (0..100_000).collect(); + let t: Vec<_> = (0..100_000).collect(); + + b.iter(|| { + let s = v + .iter() + .zip(t.iter()) + .skip(10000) + .take_while(|t| *t.0 < 10100) + .map(|(a, b)| *a + *b) + .sum::(); + assert_eq!(s, 2009900); + }); +} +#[bench] +fn bench_skip_then_zip(b: &mut Bencher) { + let v: Vec<_> = (0..100_000).collect(); + let t: Vec<_> = (0..100_000).collect(); + + b.iter(|| { + let s = v + .iter() + .skip(10000) + .zip(t.iter().skip(10000)) + .take_while(|t| *t.0 < 10100) + .map(|(a, b)| *a + *b) + .sum::(); + assert_eq!(s, 2009900); + }); +} + +#[bench] +fn bench_skip_trusted_random_access(b: &mut Bencher) { + let v: Vec = black_box(vec![42; 10000]); + let mut sink = [0; 10000]; + + b.iter(|| { + for (val, idx) in v.iter().skip(8).zip(0..10000) { + sink[idx] += val; + } + sink + }); +} + +#[bench] +fn bench_filter_count(b: &mut Bencher) { + b.iter(|| (0i64..1000000).map(black_box).filter(|x| x % 3 == 0).count()) +} + +#[bench] +fn bench_filter_ref_count(b: &mut Bencher) { + b.iter(|| (0i64..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count()) +} + +#[bench] +fn bench_filter_chain_count(b: &mut Bencher) { + b.iter(|| (0i64..1000000).chain(0..1000000).map(black_box).filter(|x| x % 3 == 0).count()) +} + +#[bench] +fn bench_filter_chain_ref_count(b: &mut Bencher) { + b.iter(|| { + (0i64..1000000).chain(0..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count() + }) +} + +#[bench] +fn bench_partial_cmp(b: &mut Bencher) { + b.iter(|| (0..100000).map(black_box).partial_cmp((0..100000).map(black_box))) +} + +#[bench] +fn bench_chain_partial_cmp(b: &mut Bencher) { + b.iter(|| { + (0..50000).chain(50000..100000).map(black_box).partial_cmp((0..100000).map(black_box)) + }) +} + +#[bench] +fn bench_lt(b: &mut Bencher) { + b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box))) +} + +#[bench] +fn bench_trusted_random_access_adapters(b: &mut Bencher) { + let vec1: Vec<_> = (0usize..100000).collect(); + let vec2 = black_box(vec1.clone()); + b.iter(|| { + let mut iter = vec1 + .iter() + .copied() + .enumerate() + .map(|(idx, e)| idx.wrapping_add(e)) + .zip(vec2.iter().copied()) + .map(|(a, b)| a.wrapping_add(b)) + .fuse(); + let mut acc: usize = 0; + let size = iter.size(); + for i in 0..size { + // SAFETY: TRA requirements are satisfied by 0..size iteration and then dropping the + // iterator. + acc = acc.wrapping_add(unsafe { iter.__iterator_get_unchecked(i) }); + } + acc + }) +} + +/// Exercises the iter::Copied specialization for slice::Iter +#[bench] +fn bench_next_chunk_copied(b: &mut Bencher) { + let v = vec![1u8; 1024]; + + b.iter(|| { + let mut iter = black_box(&v).iter().copied(); + let mut acc = Wrapping(0); + // This uses a while-let loop to side-step the TRA specialization in ArrayChunks + while let Ok(chunk) = iter.next_chunk::<{ mem::size_of::() }>() { + let d = u64::from_ne_bytes(chunk); + acc += Wrapping(d.rotate_left(7).wrapping_add(1)); + } + acc + }) +} + +/// Exercises the TrustedRandomAccess specialization in ArrayChunks +#[bench] +#[allow(noop_method_call)] +fn bench_next_chunk_trusted_random_access(b: &mut Bencher) { + let v = vec![1u8; 1024]; + + b.iter(|| { + black_box(&v) + .iter() + // this shows that we're not relying on the slice::Iter specialization in Copied + .map(|b| *b.borrow()) + .array_chunks::<{ mem::size_of::() }>() + .map(|ary| { + let d = u64::from_ne_bytes(ary); + Wrapping(d.rotate_left(7).wrapping_add(1)) + }) + .sum::>() + }) +} + +#[bench] +fn bench_next_chunk_filter_even(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter(|&&i| i % 2 == 0).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_predictably_true(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter(|&&i| i < 100).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_mostly_false(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter(|&&i| i > 900).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_map_even(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter_map(|&i| (i % 2 == 0).then(|| i)).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_map_predictably_true(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter_map(|&i| (i < 100).then(|| i)).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_map_mostly_false(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter_map(|&i| (i > 900).then(|| i)).next_chunk::<32>()) +} diff --git a/library/coretests/benches/lib.rs b/library/coretests/benches/lib.rs new file mode 100644 index 00000000000..32d15c386cb --- /dev/null +++ b/library/coretests/benches/lib.rs @@ -0,0 +1,35 @@ +// wasm32 does not support benches (no time). +#![cfg(not(target_arch = "wasm32"))] +// Disabling in Miri as these would take too long. +#![cfg(not(miri))] +#![feature(flt2dec)] +#![feature(test)] +#![feature(trusted_random_access)] +#![feature(iter_array_chunks)] +#![feature(iter_next_chunk)] +#![feature(iter_advance_by)] + +extern crate test; + +mod any; +mod array; +mod ascii; +mod char; +mod fmt; +mod hash; +mod iter; +mod net; +mod num; +mod ops; +mod pattern; +mod slice; +mod str; +mod tuple; + +/// Returns a `rand::Rng` seeded with a consistent seed. +/// +/// This is done to avoid introducing nondeterminism in benchmark results. +fn bench_rng() -> rand_xorshift::XorShiftRng { + const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + rand::SeedableRng::from_seed(SEED) +} diff --git a/library/coretests/benches/net/addr_parser.rs b/library/coretests/benches/net/addr_parser.rs new file mode 100644 index 00000000000..bbf2ea3eb97 --- /dev/null +++ b/library/coretests/benches/net/addr_parser.rs @@ -0,0 +1,78 @@ +use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use core::str::FromStr; + +use test::{Bencher, black_box}; + +const IPV4_STR: &str = "192.168.0.1"; +const IPV4_STR_PORT: &str = "192.168.0.1:8080"; + +const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; +const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; +const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; +const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; +const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080"; + +#[bench] +fn bench_parse_ipv4(b: &mut Bencher) { + b.iter(|| Ipv4Addr::from_str(black_box(IPV4_STR))); +} + +#[bench] +fn bench_parse_ipv6_full(b: &mut Bencher) { + b.iter(|| Ipv6Addr::from_str(black_box(IPV6_STR_FULL))); +} + +#[bench] +fn bench_parse_ipv6_compress(b: &mut Bencher) { + b.iter(|| Ipv6Addr::from_str(black_box(IPV6_STR_COMPRESS))); +} + +#[bench] +fn bench_parse_ipv6_v4(b: &mut Bencher) { + b.iter(|| Ipv6Addr::from_str(black_box(IPV6_STR_V4))); +} + +#[bench] +fn bench_parse_ipaddr_v4(b: &mut Bencher) { + b.iter(|| IpAddr::from_str(black_box(IPV4_STR))); +} + +#[bench] +fn bench_parse_ipaddr_v6_full(b: &mut Bencher) { + b.iter(|| IpAddr::from_str(black_box(IPV6_STR_FULL))); +} + +#[bench] +fn bench_parse_ipaddr_v6_compress(b: &mut Bencher) { + b.iter(|| IpAddr::from_str(black_box(IPV6_STR_COMPRESS))); +} + +#[bench] +fn bench_parse_ipaddr_v6_v4(b: &mut Bencher) { + b.iter(|| IpAddr::from_str(black_box(IPV6_STR_V4))); +} + +#[bench] +fn bench_parse_socket_v4(b: &mut Bencher) { + b.iter(|| SocketAddrV4::from_str(black_box(IPV4_STR_PORT))); +} + +#[bench] +fn bench_parse_socket_v6(b: &mut Bencher) { + b.iter(|| SocketAddrV6::from_str(black_box(IPV6_STR_PORT))); +} + +#[bench] +fn bench_parse_socket_v6_scope_id(b: &mut Bencher) { + b.iter(|| SocketAddrV6::from_str(black_box(IPV6_STR_PORT_SCOPE_ID))); +} + +#[bench] +fn bench_parse_socketaddr_v4(b: &mut Bencher) { + b.iter(|| SocketAddr::from_str(black_box(IPV4_STR_PORT))); +} + +#[bench] +fn bench_parse_socketaddr_v6(b: &mut Bencher) { + b.iter(|| SocketAddr::from_str(black_box(IPV6_STR_PORT))); +} diff --git a/library/coretests/benches/net/mod.rs b/library/coretests/benches/net/mod.rs new file mode 100644 index 00000000000..c29aed46ccd --- /dev/null +++ b/library/coretests/benches/net/mod.rs @@ -0,0 +1 @@ +mod addr_parser; diff --git a/library/coretests/benches/num/dec2flt/mod.rs b/library/coretests/benches/num/dec2flt/mod.rs new file mode 100644 index 00000000000..bad211f240c --- /dev/null +++ b/library/coretests/benches/num/dec2flt/mod.rs @@ -0,0 +1,57 @@ +use test::{Bencher, black_box}; + +#[bench] +fn bench_0(b: &mut Bencher) { + b.iter(|| black_box("0.0").parse::()); +} + +#[bench] +fn bench_42(b: &mut Bencher) { + b.iter(|| black_box("42").parse::()); +} + +#[bench] +fn bench_huge_int(b: &mut Bencher) { + // 2^128 - 1 + b.iter(|| black_box("170141183460469231731687303715884105727").parse::()); +} + +#[bench] +fn bench_short_decimal(b: &mut Bencher) { + b.iter(|| black_box("1234.5678").parse::()); +} + +#[bench] +fn bench_pi_long(b: &mut Bencher) { + b.iter(|| black_box("3.14159265358979323846264338327950288").parse::()); +} + +#[bench] +fn bench_pi_short(b: &mut Bencher) { + b.iter(|| black_box("3.141592653589793").parse::()) +} + +#[bench] +fn bench_1e150(b: &mut Bencher) { + b.iter(|| black_box("1e150").parse::()); +} + +#[bench] +fn bench_long_decimal_and_exp(b: &mut Bencher) { + b.iter(|| black_box("727501488517303786137132964064381141071e-123").parse::()); +} + +#[bench] +fn bench_min_subnormal(b: &mut Bencher) { + b.iter(|| black_box("5e-324").parse::()); +} + +#[bench] +fn bench_min_normal(b: &mut Bencher) { + b.iter(|| black_box("2.2250738585072014e-308").parse::()); +} + +#[bench] +fn bench_max(b: &mut Bencher) { + b.iter(|| black_box("1.7976931348623157e308").parse::()); +} diff --git a/library/coretests/benches/num/flt2dec/mod.rs b/library/coretests/benches/num/flt2dec/mod.rs new file mode 100644 index 00000000000..428d0bbbbfb --- /dev/null +++ b/library/coretests/benches/num/flt2dec/mod.rs @@ -0,0 +1,36 @@ +mod strategy { + mod dragon; + mod grisu; +} + +use core::num::flt2dec::{DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, decode}; +use std::io::Write; + +use test::{Bencher, black_box}; + +pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { + FullDecoded::Finite(decoded) => decoded, + full_decoded => panic!("expected finite, got {full_decoded:?} instead"), + } +} + +#[bench] +fn bench_small_shortest(b: &mut Bencher) { + let mut buf = Vec::with_capacity(20); + + b.iter(|| { + buf.clear(); + write!(black_box(&mut buf), "{}", black_box(3.1415926f64)).unwrap() + }); +} + +#[bench] +fn bench_big_shortest(b: &mut Bencher) { + let mut buf = Vec::with_capacity(300); + + b.iter(|| { + buf.clear(); + write!(black_box(&mut buf), "{}", black_box(f64::MAX)).unwrap() + }); +} diff --git a/library/coretests/benches/num/flt2dec/strategy/dragon.rs b/library/coretests/benches/num/flt2dec/strategy/dragon.rs new file mode 100644 index 00000000000..45266971403 --- /dev/null +++ b/library/coretests/benches/num/flt2dec/strategy/dragon.rs @@ -0,0 +1,76 @@ +use core::num::flt2dec::strategy::dragon::*; +use std::mem::MaybeUninit; + +use super::super::*; + +#[bench] +fn bench_small_shortest(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(black_box(&decoded), &mut buf); + }); +} + +#[bench] +fn bench_big_shortest(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(black_box(&decoded), &mut buf); + }); +} + +#[bench] +fn bench_small_exact_3(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_big_exact_3(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_small_exact_12(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_big_exact_12(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_small_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_big_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} diff --git a/library/coretests/benches/num/flt2dec/strategy/grisu.rs b/library/coretests/benches/num/flt2dec/strategy/grisu.rs new file mode 100644 index 00000000000..d20f9b02f7e --- /dev/null +++ b/library/coretests/benches/num/flt2dec/strategy/grisu.rs @@ -0,0 +1,110 @@ +use core::num::flt2dec::strategy::grisu::*; +use std::mem::MaybeUninit; + +use super::super::*; + +pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { + FullDecoded::Finite(decoded) => decoded, + full_decoded => panic!("expected finite, got {full_decoded:?} instead"), + } +} + +#[bench] +fn bench_small_shortest(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(black_box(&decoded), &mut buf); + }); +} + +#[bench] +fn bench_big_shortest(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(black_box(&decoded), &mut buf); + }); +} + +#[bench] +fn bench_small_exact_3(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_big_exact_3(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_small_exact_12(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_big_exact_12(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_small_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_big_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_one_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(1.0); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_trailing_zero_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(250.000000000000000000000000); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_halfway_point_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(1.00000000000000011102230246251565404236316680908203125); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} diff --git a/library/coretests/benches/num/int_log/mod.rs b/library/coretests/benches/num/int_log/mod.rs new file mode 100644 index 00000000000..e5874ddf03b --- /dev/null +++ b/library/coretests/benches/num/int_log/mod.rs @@ -0,0 +1,125 @@ +use rand::Rng; +use test::{Bencher, black_box}; + +macro_rules! int_log10_bench { + ($t:ty, $predictable:ident, $random:ident, $random_small:ident) => { + #[bench] + fn $predictable(bench: &mut Bencher) { + bench.iter(|| { + for n in 0..(<$t>::BITS / 8) { + for i in 1..=(100 as $t) { + let x = black_box(i << (n * 8)); + black_box(x.ilog10()); + } + } + }); + } + + #[bench] + fn $random(bench: &mut Bencher) { + let mut rng = crate::bench_rng(); + /* Exponentially distributed random numbers from the whole range of the type. */ + let numbers: Vec<$t> = (0..256) + .map(|_| { + let x = rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS); + if x != 0 { x } else { 1 } + }) + .collect(); + bench.iter(|| { + for x in &numbers { + black_box(black_box(x).ilog10()); + } + }); + } + + #[bench] + fn $random_small(bench: &mut Bencher) { + let mut rng = crate::bench_rng(); + /* Exponentially distributed random numbers from the range 0..256. */ + let numbers: Vec<$t> = (0..256) + .map(|_| { + let x = (rng.gen::() >> rng.gen_range(0..u8::BITS)) as $t; + if x != 0 { x } else { 1 } + }) + .collect(); + bench.iter(|| { + for x in &numbers { + black_box(black_box(x).ilog10()); + } + }); + } + }; +} + +int_log10_bench! {u8, u8_log10_predictable, u8_log10_random, u8_log10_random_small} +int_log10_bench! {u16, u16_log10_predictable, u16_log10_random, u16_log10_random_small} +int_log10_bench! {u32, u32_log10_predictable, u32_log10_random, u32_log10_random_small} +int_log10_bench! {u64, u64_log10_predictable, u64_log10_random, u64_log10_random_small} +int_log10_bench! {u128, u128_log10_predictable, u128_log10_random, u128_log10_random_small} + +macro_rules! int_log_bench { + ($t:ty, $random:ident, $random_small:ident, $geometric:ident) => { + #[bench] + fn $random(bench: &mut Bencher) { + let mut rng = crate::bench_rng(); + /* Exponentially distributed random numbers from the whole range of the type. */ + let numbers: Vec<$t> = (0..256) + .map(|_| { + let x = rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS); + if x >= 2 { x } else { 2 } + }) + .collect(); + bench.iter(|| { + for &b in &numbers { + for &x in &numbers { + black_box(black_box(x).ilog(b)); + } + } + }); + } + + #[bench] + fn $random_small(bench: &mut Bencher) { + let mut rng = crate::bench_rng(); + /* Exponentially distributed random numbers from the range 0..256. */ + let numbers: Vec<$t> = (0..256) + .map(|_| { + let x = (rng.gen::() >> rng.gen_range(0..u8::BITS)) as $t; + if x >= 2 { x } else { 2 } + }) + .collect(); + bench.iter(|| { + for &b in &numbers { + for &x in &numbers { + black_box(black_box(x).ilog(b)); + } + } + }); + } + + #[bench] + fn $geometric(bench: &mut Bencher) { + let bases: [$t; 16] = [2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65]; + let base_and_numbers: Vec<($t, Vec<$t>)> = bases + .iter() + .map(|&b| { + let numbers = (0..=<$t>::MAX.ilog(b)).map(|exp| b.pow(exp)).collect(); + (b, numbers) + }) + .collect(); + bench.iter(|| { + for (b, numbers) in &base_and_numbers { + for &x in numbers { + black_box(black_box(x).ilog(black_box(*b))); + } + } + }); + } + }; +} + +int_log_bench! {u8, u8_log_random, u8_log_random_small, u8_log_geometric} +int_log_bench! {u16, u16_log_random, u16_log_random_small, u16_log_geometric} +int_log_bench! {u32, u32_log_random, u32_log_random_small, u32_log_geometric} +int_log_bench! {u64, u64_log_random, u64_log_random_small, u64_log_geometric} +int_log_bench! {u128, u128_log_random, u128_log_random_small, u128_log_geometric} diff --git a/library/coretests/benches/num/int_pow/mod.rs b/library/coretests/benches/num/int_pow/mod.rs new file mode 100644 index 00000000000..46f47028d56 --- /dev/null +++ b/library/coretests/benches/num/int_pow/mod.rs @@ -0,0 +1,99 @@ +use rand::Rng; +use test::{Bencher, black_box}; + +const ITERATIONS: usize = 128; // Uses an ITERATIONS * 20 Byte stack allocation +type IntType = i128; // Hardest native type to multiply +const EXPONENT_MAX: u32 = 31; +const MAX_BASE: IntType = 17; // +-17 ** 31 <= IntType::MAX + +macro_rules! pow_bench_template { + ($name:ident, $inner_macro:ident, $base_macro:ident) => { + #[bench] + fn $name(bench: &mut Bencher) { + // Frequent black_box calls can add latency and prevent optimizations, so for + // variable parameters we premake an array and pass the + // reference through black_box outside of the loop. + let mut rng = crate::bench_rng(); + let base_array: [IntType; ITERATIONS] = + core::array::from_fn(|_| rng.gen_range((-MAX_BASE..=MAX_BASE))); + let exp_array: [u32; ITERATIONS] = + core::array::from_fn(|_| rng.gen_range((0..=EXPONENT_MAX))); + + bench.iter(|| { + #[allow(unused, unused_mut)] + let mut base_iter = black_box(&base_array).into_iter(); + let mut exp_iter = black_box(&exp_array).into_iter(); + + (0..ITERATIONS).fold((0 as IntType, false), |acc, _| { + // Sometimes constants don't propagate all the way to the + // inside of the loop, so we call a custom expression every cycle + // rather than iter::repeat(CONST) + let base: IntType = $base_macro!(base_iter); + let exp: u32 = *exp_iter.next().unwrap(); + + let r: (IntType, bool) = $inner_macro!(base, exp); + (acc.0 ^ r.0, acc.1 ^ r.1) + }) + }); + } + }; +} + +// This may panic if it overflows. +macro_rules! inner_pow { + ($base:ident, $exp:ident) => { + ($base.pow($exp), false) + }; +} + +macro_rules! inner_wrapping { + ($base:ident, $exp:ident) => { + ($base.wrapping_pow($exp), false) + }; +} + +macro_rules! inner_overflowing { + ($base:ident, $exp:ident) => { + $base.overflowing_pow($exp) + }; +} + +// This will panic if it overflows. +macro_rules! inner_checked_unwrapped { + ($base:ident, $exp:ident) => { + ($base.checked_pow($exp).unwrap(), false) + }; +} + +macro_rules! inner_saturating { + ($base:ident, $exp:ident) => { + ($base.saturating_pow($exp), false) + }; +} + +macro_rules! make_const_base { + ($name:ident, $x:literal) => { + macro_rules! $name { + ($iter:ident) => { + $x + }; + } + }; +} + +make_const_base!(const_base_m7, -7); +make_const_base!(const_base_m8, -8); + +macro_rules! variable_base { + ($iter:ident) => { + *$iter.next().unwrap() + }; +} + +pow_bench_template!(pow_variable, inner_pow, variable_base); +pow_bench_template!(wrapping_pow_variable, inner_wrapping, variable_base); +pow_bench_template!(overflowing_pow_variable, inner_overflowing, variable_base); +pow_bench_template!(checked_pow_variable, inner_checked_unwrapped, variable_base); +pow_bench_template!(saturating_pow_variable, inner_saturating, variable_base); +pow_bench_template!(pow_m7, inner_pow, const_base_m7); +pow_bench_template!(pow_m8, inner_pow, const_base_m8); diff --git a/library/coretests/benches/num/int_sqrt/mod.rs b/library/coretests/benches/num/int_sqrt/mod.rs new file mode 100644 index 00000000000..e47b92e866e --- /dev/null +++ b/library/coretests/benches/num/int_sqrt/mod.rs @@ -0,0 +1,62 @@ +use rand::Rng; +use test::{Bencher, black_box}; + +macro_rules! int_sqrt_bench { + ($t:ty, $predictable:ident, $random:ident, $random_small:ident, $random_uniform:ident) => { + #[bench] + fn $predictable(bench: &mut Bencher) { + bench.iter(|| { + for n in 0..(<$t>::BITS / 8) { + for i in 1..=(100 as $t) { + let x = black_box(i << (n * 8)); + black_box(x.isqrt()); + } + } + }); + } + + #[bench] + fn $random(bench: &mut Bencher) { + let mut rng = crate::bench_rng(); + /* Exponentially distributed random numbers from the whole range of the type. */ + let numbers: Vec<$t> = + (0..256).map(|_| rng.gen::<$t>() >> rng.gen_range(0..<$t>::BITS)).collect(); + bench.iter(|| { + for x in &numbers { + black_box(black_box(x).isqrt()); + } + }); + } + + #[bench] + fn $random_small(bench: &mut Bencher) { + let mut rng = crate::bench_rng(); + /* Exponentially distributed random numbers from the range 0..256. */ + let numbers: Vec<$t> = + (0..256).map(|_| (rng.gen::() >> rng.gen_range(0..u8::BITS)) as $t).collect(); + bench.iter(|| { + for x in &numbers { + black_box(black_box(x).isqrt()); + } + }); + } + + #[bench] + fn $random_uniform(bench: &mut Bencher) { + let mut rng = crate::bench_rng(); + /* Exponentially distributed random numbers from the whole range of the type. */ + let numbers: Vec<$t> = (0..256).map(|_| rng.gen::<$t>()).collect(); + bench.iter(|| { + for x in &numbers { + black_box(black_box(x).isqrt()); + } + }); + } + }; +} + +int_sqrt_bench! {u8, u8_sqrt_predictable, u8_sqrt_random, u8_sqrt_random_small, u8_sqrt_uniform} +int_sqrt_bench! {u16, u16_sqrt_predictable, u16_sqrt_random, u16_sqrt_random_small, u16_sqrt_uniform} +int_sqrt_bench! {u32, u32_sqrt_predictable, u32_sqrt_random, u32_sqrt_random_small, u32_sqrt_uniform} +int_sqrt_bench! {u64, u64_sqrt_predictable, u64_sqrt_random, u64_sqrt_random_small, u64_sqrt_uniform} +int_sqrt_bench! {u128, u128_sqrt_predictable, u128_sqrt_random, u128_sqrt_random_small, u128_sqrt_uniform} diff --git a/library/coretests/benches/num/mod.rs b/library/coretests/benches/num/mod.rs new file mode 100644 index 00000000000..b36100e59a9 --- /dev/null +++ b/library/coretests/benches/num/mod.rs @@ -0,0 +1,111 @@ +mod dec2flt; +mod flt2dec; +mod int_log; +mod int_pow; +mod int_sqrt; + +use std::str::FromStr; + +use test::{Bencher, black_box}; + +const ASCII_NUMBERS: [&str; 19] = [ + "0", + "1", + "2", + "43", + "765", + "76567", + "987245987", + "-4aa32", + "1786235", + "8723095", + "f##5s", + "83638730", + "-2345", + "562aa43", + "-1", + "-0", + "abc", + "xyz", + "c0ffee", +]; + +macro_rules! from_str_bench { + ($mac:ident, $t:ty) => { + #[bench] + fn $mac(b: &mut Bencher) { + b.iter(|| { + ASCII_NUMBERS + .iter() + .cycle() + .take(5_000) + .filter_map(|s| <$t>::from_str(black_box(s)).ok()) + .max() + }) + } + }; +} + +macro_rules! from_str_radix_bench { + ($mac:ident, $t:ty, $radix:expr) => { + #[bench] + fn $mac(b: &mut Bencher) { + b.iter(|| { + ASCII_NUMBERS + .iter() + .cycle() + .take(5_000) + .filter_map(|s| <$t>::from_str_radix(black_box(s), $radix).ok()) + .max() + }) + } + }; +} + +from_str_bench!(bench_u8_from_str, u8); +from_str_radix_bench!(bench_u8_from_str_radix_2, u8, 2); +from_str_radix_bench!(bench_u8_from_str_radix_10, u8, 10); +from_str_radix_bench!(bench_u8_from_str_radix_16, u8, 16); +from_str_radix_bench!(bench_u8_from_str_radix_36, u8, 36); + +from_str_bench!(bench_u16_from_str, u16); +from_str_radix_bench!(bench_u16_from_str_radix_2, u16, 2); +from_str_radix_bench!(bench_u16_from_str_radix_10, u16, 10); +from_str_radix_bench!(bench_u16_from_str_radix_16, u16, 16); +from_str_radix_bench!(bench_u16_from_str_radix_36, u16, 36); + +from_str_bench!(bench_u32_from_str, u32); +from_str_radix_bench!(bench_u32_from_str_radix_2, u32, 2); +from_str_radix_bench!(bench_u32_from_str_radix_10, u32, 10); +from_str_radix_bench!(bench_u32_from_str_radix_16, u32, 16); +from_str_radix_bench!(bench_u32_from_str_radix_36, u32, 36); + +from_str_bench!(bench_u64_from_str, u64); +from_str_radix_bench!(bench_u64_from_str_radix_2, u64, 2); +from_str_radix_bench!(bench_u64_from_str_radix_10, u64, 10); +from_str_radix_bench!(bench_u64_from_str_radix_16, u64, 16); +from_str_radix_bench!(bench_u64_from_str_radix_36, u64, 36); + +from_str_bench!(bench_i8_from_str, i8); +from_str_radix_bench!(bench_i8_from_str_radix_2, i8, 2); +from_str_radix_bench!(bench_i8_from_str_radix_10, i8, 10); +from_str_radix_bench!(bench_i8_from_str_radix_16, i8, 16); +from_str_radix_bench!(bench_i8_from_str_radix_36, i8, 36); + +from_str_bench!(bench_i16_from_str, i16); +from_str_radix_bench!(bench_i16_from_str_radix_2, i16, 2); +from_str_radix_bench!(bench_i16_from_str_radix_10, i16, 10); +from_str_radix_bench!(bench_i16_from_str_radix_16, i16, 16); +from_str_radix_bench!(bench_i16_from_str_radix_36, i16, 36); + +from_str_bench!(bench_i32_from_str, i32); +from_str_radix_bench!(bench_i32_from_str_radix_2, i32, 2); +from_str_radix_bench!(bench_i32_from_str_radix_10, i32, 10); +from_str_radix_bench!(bench_i32_from_str_radix_16, i32, 16); +from_str_radix_bench!(bench_i32_from_str_radix_36, i32, 36); + +from_str_bench!(bench_i64_from_str, i64); +from_str_radix_bench!(bench_i64_from_str_radix_2, i64, 2); +from_str_radix_bench!(bench_i64_from_str_radix_10, i64, 10); +from_str_radix_bench!(bench_i64_from_str_radix_16, i64, 16); +from_str_radix_bench!(bench_i64_from_str_radix_36, i64, 36); diff --git a/library/coretests/benches/ops.rs b/library/coretests/benches/ops.rs new file mode 100644 index 00000000000..3d0b3302957 --- /dev/null +++ b/library/coretests/benches/ops.rs @@ -0,0 +1,20 @@ +use core::ops::*; + +use test::Bencher; + +// Overhead of dtors + +struct HasDtor { + _x: isize, +} + +impl Drop for HasDtor { + fn drop(&mut self) {} +} + +#[bench] +fn alloc_obj_with_dtor(b: &mut Bencher) { + b.iter(|| { + HasDtor { _x: 10 }; + }) +} diff --git a/library/coretests/benches/pattern.rs b/library/coretests/benches/pattern.rs new file mode 100644 index 00000000000..b0f8b39c22e --- /dev/null +++ b/library/coretests/benches/pattern.rs @@ -0,0 +1,41 @@ +use test::{Bencher, black_box}; + +#[bench] +fn starts_with_char(b: &mut Bencher) { + let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind"); + b.iter(|| { + for _ in 0..1024 { + black_box(text.starts_with('k')); + } + }) +} + +#[bench] +fn starts_with_str(b: &mut Bencher) { + let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind"); + b.iter(|| { + for _ in 0..1024 { + black_box(text.starts_with("k")); + } + }) +} + +#[bench] +fn ends_with_char(b: &mut Bencher) { + let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind"); + b.iter(|| { + for _ in 0..1024 { + black_box(text.ends_with('k')); + } + }) +} + +#[bench] +fn ends_with_str(b: &mut Bencher) { + let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind"); + b.iter(|| { + for _ in 0..1024 { + black_box(text.ends_with("k")); + } + }) +} diff --git a/library/coretests/benches/slice.rs b/library/coretests/benches/slice.rs new file mode 100644 index 00000000000..29a66b62199 --- /dev/null +++ b/library/coretests/benches/slice.rs @@ -0,0 +1,173 @@ +use core::ptr::NonNull; + +use test::{Bencher, black_box}; + +enum Cache { + L1, + L2, + L3, +} + +impl Cache { + fn size(&self) -> usize { + match self { + Cache::L1 => 1000, // 8kb + Cache::L2 => 10_000, // 80kb + Cache::L3 => 1_000_000, // 8Mb + } + } +} + +fn binary_search(b: &mut Bencher, cache: Cache, mapper: F) +where + F: Fn(usize) -> usize, +{ + let size = cache.size(); + let v = (0..size).map(&mapper).collect::>(); + let mut r = 0usize; + b.iter(move || { + // LCG constants from https://en.wikipedia.org/wiki/Numerical_Recipes. + r = r.wrapping_mul(1664525).wrapping_add(1013904223); + // Lookup the whole range to get 50% hits and 50% misses. + let i = mapper(r % size); + black_box(v.binary_search(&i).is_ok()); + }); +} + +fn binary_search_worst_case(b: &mut Bencher, cache: Cache) { + let size = cache.size(); + + let mut v = vec![0; size]; + let i = 1; + v[size - 1] = i; + b.iter(move || { + black_box(v.binary_search(&i).is_ok()); + }); +} + +#[bench] +fn binary_search_l1(b: &mut Bencher) { + binary_search(b, Cache::L1, |i| i * 2); +} + +#[bench] +fn binary_search_l2(b: &mut Bencher) { + binary_search(b, Cache::L2, |i| i * 2); +} + +#[bench] +fn binary_search_l3(b: &mut Bencher) { + binary_search(b, Cache::L3, |i| i * 2); +} + +#[bench] +fn binary_search_l1_with_dups(b: &mut Bencher) { + binary_search(b, Cache::L1, |i| i / 16 * 16); +} + +#[bench] +fn binary_search_l2_with_dups(b: &mut Bencher) { + binary_search(b, Cache::L2, |i| i / 16 * 16); +} + +#[bench] +fn binary_search_l3_with_dups(b: &mut Bencher) { + binary_search(b, Cache::L3, |i| i / 16 * 16); +} + +#[bench] +fn binary_search_l1_worst_case(b: &mut Bencher) { + binary_search_worst_case(b, Cache::L1); +} + +#[bench] +fn binary_search_l2_worst_case(b: &mut Bencher) { + binary_search_worst_case(b, Cache::L2); +} + +#[bench] +fn binary_search_l3_worst_case(b: &mut Bencher) { + binary_search_worst_case(b, Cache::L3); +} + +#[derive(Clone)] +struct Rgb(#[allow(dead_code)] u8, #[allow(dead_code)] u8, #[allow(dead_code)] u8); + +impl Rgb { + fn gen(i: usize) -> Self { + Rgb(i as u8, (i as u8).wrapping_add(7), (i as u8).wrapping_add(42)) + } +} + +macro_rules! rotate { + ($fn:ident, $n:expr, $mapper:expr) => { + #[bench] + fn $fn(b: &mut Bencher) { + let mut x = (0usize..$n).map(&$mapper).collect::>(); + b.iter(|| { + for s in 0..x.len() { + x[..].rotate_right(s); + } + black_box(x[0].clone()) + }) + } + }; +} + +rotate!(rotate_u8, 32, |i| i as u8); +rotate!(rotate_rgb, 32, Rgb::gen); +rotate!(rotate_usize, 32, |i| i); +rotate!(rotate_16_usize_4, 16, |i| [i; 4]); +rotate!(rotate_16_usize_5, 16, |i| [i; 5]); +rotate!(rotate_64_usize_4, 64, |i| [i; 4]); +rotate!(rotate_64_usize_5, 64, |i| [i; 5]); + +macro_rules! swap_with_slice { + ($fn:ident, $n:expr, $mapper:expr) => { + #[bench] + fn $fn(b: &mut Bencher) { + let mut x = (0usize..$n).map(&$mapper).collect::>(); + let mut y = ($n..($n * 2)).map(&$mapper).collect::>(); + let mut skip = 0; + b.iter(|| { + for _ in 0..32 { + x[skip..].swap_with_slice(&mut y[..($n - skip)]); + skip = black_box(skip + 1) % 8; + } + black_box((x[$n / 3].clone(), y[$n * 2 / 3].clone())) + }) + } + }; +} + +swap_with_slice!(swap_with_slice_u8_30, 30, |i| i as u8); +swap_with_slice!(swap_with_slice_u8_3000, 3000, |i| i as u8); +swap_with_slice!(swap_with_slice_rgb_30, 30, Rgb::gen); +swap_with_slice!(swap_with_slice_rgb_3000, 3000, Rgb::gen); +swap_with_slice!(swap_with_slice_usize_30, 30, |i| i); +swap_with_slice!(swap_with_slice_usize_3000, 3000, |i| i); +swap_with_slice!(swap_with_slice_4x_usize_30, 30, |i| [i; 4]); +swap_with_slice!(swap_with_slice_4x_usize_3000, 3000, |i| [i; 4]); +swap_with_slice!(swap_with_slice_5x_usize_30, 30, |i| [i; 5]); +swap_with_slice!(swap_with_slice_5x_usize_3000, 3000, |i| [i; 5]); + +#[bench] +fn fill_byte_sized(b: &mut Bencher) { + #[derive(Copy, Clone)] + struct NewType(#[allow(dead_code)] u8); + + let mut ary = [NewType(0); 1024]; + + b.iter(|| { + let slice = &mut ary[..]; + black_box(slice.fill(black_box(NewType(42)))); + }); +} + +// Tests the ability of the compiler to recognize that only the last slice item is needed +// based on issue #106288 +#[bench] +fn fold_to_last(b: &mut Bencher) { + let slice: &[i32] = &[0; 1024]; + b.iter(|| black_box(slice).iter().fold(None, |_, r| Some(NonNull::from(r)))); +} diff --git a/library/coretests/benches/str.rs b/library/coretests/benches/str.rs new file mode 100644 index 00000000000..2f7d9d56a70 --- /dev/null +++ b/library/coretests/benches/str.rs @@ -0,0 +1,13 @@ +use std::str; + +use test::{Bencher, black_box}; + +mod char_count; +mod corpora; +mod debug; +mod iter; + +#[bench] +fn str_validate_emoji(b: &mut Bencher) { + b.iter(|| str::from_utf8(black_box(corpora::emoji::LARGE.as_bytes()))); +} diff --git a/library/coretests/benches/str/char_count.rs b/library/coretests/benches/str/char_count.rs new file mode 100644 index 00000000000..343e23dcf41 --- /dev/null +++ b/library/coretests/benches/str/char_count.rs @@ -0,0 +1,108 @@ +use test::{Bencher, black_box}; + +use super::corpora::*; + +macro_rules! define_benches { + ($( fn $name: ident($arg: ident: &str) $body: block )+) => { + define_benches!(mod en_tiny, en::TINY, $($name $arg $body)+); + define_benches!(mod en_small, en::SMALL, $($name $arg $body)+); + define_benches!(mod en_medium, en::MEDIUM, $($name $arg $body)+); + define_benches!(mod en_large, en::LARGE, $($name $arg $body)+); + define_benches!(mod en_huge, en::HUGE, $($name $arg $body)+); + + define_benches!(mod zh_tiny, zh::TINY, $($name $arg $body)+); + define_benches!(mod zh_small, zh::SMALL, $($name $arg $body)+); + define_benches!(mod zh_medium, zh::MEDIUM, $($name $arg $body)+); + define_benches!(mod zh_large, zh::LARGE, $($name $arg $body)+); + define_benches!(mod zh_huge, zh::HUGE, $($name $arg $body)+); + + define_benches!(mod ru_tiny, ru::TINY, $($name $arg $body)+); + define_benches!(mod ru_small, ru::SMALL, $($name $arg $body)+); + define_benches!(mod ru_medium, ru::MEDIUM, $($name $arg $body)+); + define_benches!(mod ru_large, ru::LARGE, $($name $arg $body)+); + define_benches!(mod ru_huge, ru::HUGE, $($name $arg $body)+); + + define_benches!(mod emoji_tiny, emoji::TINY, $($name $arg $body)+); + define_benches!(mod emoji_small, emoji::SMALL, $($name $arg $body)+); + define_benches!(mod emoji_medium, emoji::MEDIUM, $($name $arg $body)+); + define_benches!(mod emoji_large, emoji::LARGE, $($name $arg $body)+); + define_benches!(mod emoji_huge, emoji::HUGE, $($name $arg $body)+); + }; + (mod $mod_name: ident, $input: expr, $($name: ident $arg: ident $body: block)+) => { + mod $mod_name { + use super::*; + $( + #[bench] + fn $name(bencher: &mut Bencher) { + let input = $input; + bencher.bytes = input.len() as u64; + let mut input_s = input.to_string(); + bencher.iter(|| { + let $arg: &str = &black_box(&mut input_s); + black_box($body) + }) + } + )+ + } + }; +} + +define_benches! { + fn case00_libcore(s: &str) { + libcore(s) + } + + fn case01_filter_count_cont_bytes(s: &str) { + filter_count_cont_bytes(s) + } + + fn case02_iter_increment(s: &str) { + iterator_increment(s) + } + + fn case03_manual_char_len(s: &str) { + manual_char_len(s) + } +} + +fn libcore(s: &str) -> usize { + s.chars().count() +} + +#[inline] +fn utf8_is_cont_byte(byte: u8) -> bool { + (byte as i8) < -64 +} + +fn filter_count_cont_bytes(s: &str) -> usize { + s.as_bytes().iter().filter(|&&byte| !utf8_is_cont_byte(byte)).count() +} + +fn iterator_increment(s: &str) -> usize { + let mut c = 0; + for _ in s.chars() { + c += 1; + } + c +} + +fn manual_char_len(s: &str) -> usize { + let s = s.as_bytes(); + let mut c = 0; + let mut i = 0; + let l = s.len(); + while i < l { + let b = s[i]; + if b < 0x80 { + i += 1; + } else if b < 0xe0 { + i += 2; + } else if b < 0xf0 { + i += 3; + } else { + i += 4; + } + c += 1; + } + c +} diff --git a/library/coretests/benches/str/corpora.rs b/library/coretests/benches/str/corpora.rs new file mode 100644 index 00000000000..b4ac625061d --- /dev/null +++ b/library/coretests/benches/str/corpora.rs @@ -0,0 +1,88 @@ +//! Exposes a number of modules with different kinds of strings. +//! +//! Each module contains `&str` constants named `TINY`, `SMALL`, `MEDIUM`, +//! `LARGE`, and `HUGE`. +//! +//! - The `TINY` string is generally around 8 bytes. +//! - The `SMALL` string is generally around 30-40 bytes. +//! - The `MEDIUM` string is generally around 600-700 bytes. +//! - The `LARGE` string is the `MEDIUM` string repeated 8x, and is around 5kb. +//! - The `HUGE` string is the `LARGE` string repeated 8x (or the `MEDIUM` +//! string repeated 64x), and is around 40kb. +//! +//! Except for `mod emoji` (which is just a bunch of emoji), the strings were +//! pulled from (localizations of) rust-lang.org. + +macro_rules! repeat8 { + ($s:expr) => { + concat!($s, $s, $s, $s, $s, $s, $s, $s) + }; +} + +macro_rules! define_consts { + ($s:literal) => { + pub const MEDIUM: &str = $s; + pub const LARGE: &str = repeat8!($s); + pub const HUGE: &str = repeat8!(repeat8!(repeat8!($s))); + }; +} + +pub mod en { + pub const TINY: &str = "Mary had"; + pub const SMALL: &str = "Mary had a little lamb, Little lamb"; + define_consts! { + "Rust is blazingly fast and memory-efficient: with no runtime or garbage + collector, it can power performance-critical services, run on embedded + devices, and easily integrate with other languages. Rust’s rich type system + and ownership model guarantee memory-safety and thread-safety — enabling you + to eliminate many classes of bugs at compile-time. Rust has great + documentation, a friendly compiler with useful error messages, and top-notch + tooling — an integrated package manager and build tool, smart multi-editor + support with auto-completion and type inspections, an auto-formatter, and + more." + } +} + +pub mod zh { + pub const TINY: &str = "速度惊"; + pub const SMALL: &str = "速度惊人且内存利用率极高"; + define_consts! { + "Rust 速度惊人且内存利用率极高。由于\ + 没有运行时和垃圾回收,它能够胜任对性能要\ + 求特别高的服务,可以在嵌入式设备上运行,\ + 还能轻松和其他语言集成。Rust 丰富的类型\ + 系统和所有权模型保证了内存安全和线程安全,\ + 让您在编译期就能够消除各种各样的错误。\ + Rust 拥有出色的文档、友好的编译器和清晰\ + 的错误提示信息, 还集成了一流的工具——\ + 包管理器和构建工具, 智能地自动补全和类\ + 型检验的多编辑器支持, 以及自动格式化代\ + 码等等。" + } +} + +pub mod ru { + pub const TINY: &str = "Сотни"; + pub const SMALL: &str = "Сотни компаний по"; + define_consts! { + "Сотни компаний по всему миру используют Rust в реальных\ + проектах для быстрых кросс-платформенных решений с\ + ограниченными ресурсами. Такие проекты, как Firefox,\ + Dropbox и Cloudflare, используют Rust. Rust отлично\ + подходит как для стартапов, так и для больших компаний,\ + как для встраиваемых устройств, так и для масштабируемых\ + web-сервисов. Мой самый большой комплимент Rust." + } +} + +pub mod emoji { + pub const TINY: &str = "😀😃"; + pub const SMALL: &str = "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘"; + define_consts! { + "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗☺😚😙🥲😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😶‍🌫️😏😒\ + 🙄😬😮‍💨🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵😵‍💫🤯��🥳🥸😎🤓🧐😕😟🙁☹😮😯😲😳🥺😦😧😨\ + 😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬😈👿💀☠💩🤡👹👺👻👽👾🤖😺😸😹😻😼😽🙀😿😾🙈🙉🙊\ + 💋💌💘💝💖💗💓��💕💟❣💔❤️‍🔥❤️‍🩹❤🧡💛💚💙💜🤎🖤🤍💯💢💥💫💦💨🕳💬👁️‍🗨️🗨🗯💭💤👋\ + 🤚🖐✋🖖👌🤌🤏✌" + } +} diff --git a/library/coretests/benches/str/debug.rs b/library/coretests/benches/str/debug.rs new file mode 100644 index 00000000000..e41d4fa110a --- /dev/null +++ b/library/coretests/benches/str/debug.rs @@ -0,0 +1,80 @@ +//! This primarily benchmarks `impl Debug for str`, +//! and it also explicitly tests that we minimizes calls to the underlying `Write`r. +//! While that is an implementation detail and there are no guarantees about it, +//! we should still try to minimize those calls over time rather than regress them. + +use std::fmt::{self, Write}; + +use test::{Bencher, black_box}; + +#[derive(Default)] +struct CountingWriter { + buf: String, + write_calls: usize, +} + +impl Write for CountingWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.buf.push_str(s); + self.write_calls += 1; + Ok(()) + } +} + +fn assert_fmt(s: &str, expected: &str, expected_write_calls: usize) { + let mut w = CountingWriter::default(); + + write!(&mut w, "{s:?}").unwrap(); + assert_eq!(s.len(), 64); + assert_eq!(w.buf, expected); + assert_eq!(w.write_calls, expected_write_calls); +} + +#[bench] +fn ascii_only(b: &mut Bencher) { + let s = "just a bit of ascii text that has no escapes. 64 bytes exactly!!"; + assert_fmt(s, r#""just a bit of ascii text that has no escapes. 64 bytes exactly!!""#, 3); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} + +#[bench] +fn ascii_escapes(b: &mut Bencher) { + let s = "some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte"; + assert_fmt( + s, + r#""some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte""#, + 15, + ); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} + +#[bench] +fn some_unicode(b: &mut Bencher) { + let s = "egy kis szöveg néhány unicode betűvel. legyen ez is 64 byte."; + assert_fmt(s, r#""egy kis szöveg néhány unicode betűvel. legyen ez is 64 byte.""#, 3); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} + +#[bench] +fn mostly_unicode(b: &mut Bencher) { + let s = "предложение из кириллических букв."; + assert_fmt(s, r#""предложение из кириллических букв.""#, 3); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} + +#[bench] +fn mixed(b: &mut Bencher) { + let s = "\"❤️\"\n\"hűha ez betű\"\n\"кириллических букв\"."; + assert_fmt(s, r#""\"❤\u{fe0f}\"\n\"hűha ez betű\"\n\"кириллических букв\".""#, 21); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} diff --git a/library/coretests/benches/str/iter.rs b/library/coretests/benches/str/iter.rs new file mode 100644 index 00000000000..d2586cef258 --- /dev/null +++ b/library/coretests/benches/str/iter.rs @@ -0,0 +1,18 @@ +use test::{Bencher, black_box}; + +use super::corpora; + +#[bench] +fn chars_advance_by_1000(b: &mut Bencher) { + b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(1000)); +} + +#[bench] +fn chars_advance_by_0010(b: &mut Bencher) { + b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(10)); +} + +#[bench] +fn chars_advance_by_0001(b: &mut Bencher) { + b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(1)); +} diff --git a/library/coretests/benches/tuple.rs b/library/coretests/benches/tuple.rs new file mode 100644 index 00000000000..dcda7c641aa --- /dev/null +++ b/library/coretests/benches/tuple.rs @@ -0,0 +1,22 @@ +use rand::prelude::*; +use test::{Bencher, black_box}; + +#[bench] +fn bench_tuple_comparison(b: &mut Bencher) { + let mut rng = black_box(super::bench_rng()); + + let data = black_box([ + ("core::iter::adapters::Chain", 123_usize), + ("core::iter::adapters::Clone", 456_usize), + ("core::iter::adapters::Copie", 789_usize), + ("core::iter::adapters::Cycle", 123_usize), + ("core::iter::adapters::Flatt", 456_usize), + ("core::iter::adapters::TakeN", 789_usize), + ]); + + b.iter(|| { + let x = data.choose(&mut rng).unwrap(); + let y = data.choose(&mut rng).unwrap(); + [x < y, x <= y, x > y, x >= y] + }); +} diff --git a/library/coretests/lib.rs b/library/coretests/lib.rs new file mode 100644 index 00000000000..b49208cd4eb --- /dev/null +++ b/library/coretests/lib.rs @@ -0,0 +1 @@ +// Intentionally left empty. diff --git a/library/coretests/tests/alloc.rs b/library/coretests/tests/alloc.rs new file mode 100644 index 00000000000..b88f1821cd7 --- /dev/null +++ b/library/coretests/tests/alloc.rs @@ -0,0 +1,75 @@ +use core::alloc::Layout; +use core::mem::size_of; +use core::ptr::{self, NonNull}; + +#[test] +fn const_unchecked_layout() { + const SIZE: usize = 0x2000; + const ALIGN: usize = 0x1000; + const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) }; + const DANGLING: NonNull = LAYOUT.dangling(); + assert_eq!(LAYOUT.size(), SIZE); + assert_eq!(LAYOUT.align(), ALIGN); + assert_eq!(Some(DANGLING), NonNull::new(ptr::without_provenance_mut(ALIGN))); +} + +#[test] +fn layout_round_up_to_align_edge_cases() { + const MAX_SIZE: usize = isize::MAX as usize; + + for shift in 0..usize::BITS { + let align = 1_usize << shift; + let edge = (MAX_SIZE + 1) - align; + let low = edge.saturating_sub(10); + let high = edge.saturating_add(10); + assert!(Layout::from_size_align(low, align).is_ok()); + assert!(Layout::from_size_align(high, align).is_err()); + for size in low..=high { + assert_eq!( + Layout::from_size_align(size, align).is_ok(), + size.next_multiple_of(align) <= MAX_SIZE, + ); + } + } +} + +#[test] +fn layout_array_edge_cases() { + for_type::(); + for_type::<[i32; 0b10101]>(); + for_type::<[u8; 0b1010101]>(); + + // Make sure ZSTs don't lead to divide-by-zero + assert_eq!(Layout::array::<()>(usize::MAX).unwrap(), Layout::from_size_align(0, 1).unwrap()); + + fn for_type() { + const MAX_SIZE: usize = isize::MAX as usize; + + let edge = (MAX_SIZE + 1) / size_of::(); + let low = edge.saturating_sub(10); + let high = edge.saturating_add(10); + assert!(Layout::array::(low).is_ok()); + assert!(Layout::array::(high).is_err()); + for n in low..=high { + assert_eq!(Layout::array::(n).is_ok(), n * size_of::() <= MAX_SIZE); + } + } +} + +#[test] +fn layout_debug_shows_log2_of_alignment() { + // `Debug` is not stable, but here's what it does right now + let layout = Layout::from_size_align(24576, 8192).unwrap(); + let s = format!("{:?}", layout); + assert_eq!(s, "Layout { size: 24576, align: 8192 (1 << 13) }"); +} + +// Running this normally doesn't do much, but it's also run in Miri, which +// will double-check that these are allowed by the validity invariants. +#[test] +fn layout_accepts_all_valid_alignments() { + for align in 0..usize::BITS { + let layout = Layout::from_size_align(0, 1_usize << align).unwrap(); + assert_eq!(layout.align(), 1_usize << align); + } +} diff --git a/library/coretests/tests/any.rs b/library/coretests/tests/any.rs new file mode 100644 index 00000000000..25002617d0b --- /dev/null +++ b/library/coretests/tests/any.rs @@ -0,0 +1,149 @@ +use core::any::*; + +#[derive(PartialEq, Debug)] +struct Test; + +static TEST: &'static str = "Test"; + +#[test] +fn any_referenced() { + let (a, b, c) = (&5 as &dyn Any, &TEST as &dyn Any, &Test as &dyn Any); + + assert!(a.is::()); + assert!(!b.is::()); + assert!(!c.is::()); + + assert!(!a.is::<&'static str>()); + assert!(b.is::<&'static str>()); + assert!(!c.is::<&'static str>()); + + assert!(!a.is::()); + assert!(!b.is::()); + assert!(c.is::()); +} + +#[test] +fn any_owning() { + let (a, b, c) = ( + Box::new(5_usize) as Box, + Box::new(TEST) as Box, + Box::new(Test) as Box, + ); + + assert!(a.is::()); + assert!(!b.is::()); + assert!(!c.is::()); + + assert!(!a.is::<&'static str>()); + assert!(b.is::<&'static str>()); + assert!(!c.is::<&'static str>()); + + assert!(!a.is::()); + assert!(!b.is::()); + assert!(c.is::()); +} + +#[test] +fn any_downcast_ref() { + let a = &5_usize as &dyn Any; + + match a.downcast_ref::() { + Some(&5) => {} + x => panic!("Unexpected value {x:?}"), + } + + match a.downcast_ref::() { + None => {} + x => panic!("Unexpected value {x:?}"), + } +} + +#[test] +fn any_downcast_mut() { + let mut a = 5_usize; + let mut b: Box<_> = Box::new(7_usize); + + let a_r = &mut a as &mut dyn Any; + let tmp: &mut usize = &mut *b; + let b_r = tmp as &mut dyn Any; + + match a_r.downcast_mut::() { + Some(x) => { + assert_eq!(*x, 5); + *x = 612; + } + x => panic!("Unexpected value {x:?}"), + } + + match b_r.downcast_mut::() { + Some(x) => { + assert_eq!(*x, 7); + *x = 413; + } + x => panic!("Unexpected value {x:?}"), + } + + match a_r.downcast_mut::() { + None => (), + x => panic!("Unexpected value {x:?}"), + } + + match b_r.downcast_mut::() { + None => (), + x => panic!("Unexpected value {x:?}"), + } + + match a_r.downcast_mut::() { + Some(&mut 612) => {} + x => panic!("Unexpected value {x:?}"), + } + + match b_r.downcast_mut::() { + Some(&mut 413) => {} + x => panic!("Unexpected value {x:?}"), + } +} + +#[test] +fn any_fixed_vec() { + let test = [0_usize; 8]; + let test = &test as &dyn Any; + assert!(test.is::<[usize; 8]>()); + assert!(!test.is::<[usize; 10]>()); +} + +#[test] +fn any_unsized() { + fn is_any() {} + is_any::<[i32]>(); +} + +#[test] +fn distinct_type_names() { + // https://github.com/rust-lang/rust/issues/84666 + + struct Velocity(#[allow(dead_code)] f32, #[allow(dead_code)] f32); + + fn type_name_of_val(_: T) -> &'static str { + type_name::() + } + + assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),); +} + +#[test] +fn dyn_type_name() { + trait Foo { + type Bar; + } + + assert_eq!( + "dyn core::ops::function::Fn(i32, i32) -> i32", + std::any::type_name:: i32>() + ); + assert_eq!( + "dyn coretests::any::dyn_type_name::Foo \ + + core::marker::Send + core::marker::Sync", + std::any::type_name:: + Send + Sync>() + ); +} diff --git a/library/coretests/tests/array.rs b/library/coretests/tests/array.rs new file mode 100644 index 00000000000..b6d18f1ec38 --- /dev/null +++ b/library/coretests/tests/array.rs @@ -0,0 +1,719 @@ +use core::num::NonZero; +use core::sync::atomic::{AtomicUsize, Ordering}; +use core::{array, assert_eq}; + +#[test] +fn array_from_ref() { + let value: String = "Hello World!".into(); + let arr: &[String; 1] = array::from_ref(&value); + assert_eq!(&[value.clone()], arr); + + const VALUE: &&str = &"Hello World!"; + const ARR: &[&str; 1] = array::from_ref(VALUE); + assert_eq!(&[*VALUE], ARR); + assert!(core::ptr::eq(VALUE, &ARR[0])); +} + +#[test] +fn array_from_mut() { + let mut value: String = "Hello World".into(); + let arr: &mut [String; 1] = array::from_mut(&mut value); + arr[0].push_str("!"); + assert_eq!(&value, "Hello World!"); +} + +#[test] +fn array_try_from() { + macro_rules! test { + ($($N:expr)+) => { + $({ + type Array = [u8; $N]; + let mut array: Array = [0; $N]; + let slice: &[u8] = &array[..]; + + let result = <&Array>::try_from(slice); + assert_eq!(&array, result.unwrap()); + + let result = ::try_from(slice); + assert_eq!(&array, &result.unwrap()); + + let mut_slice: &mut [u8] = &mut array[..]; + let result = <&mut Array>::try_from(mut_slice); + assert_eq!(&[0; $N], result.unwrap()); + + let mut_slice: &mut [u8] = &mut array[..]; + let result = ::try_from(mut_slice); + assert_eq!(&array, &result.unwrap()); + })+ + } + } + test! { + 0 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 27 28 29 + 30 31 32 + } +} + +#[test] +fn iterator_collect() { + let arr = [0, 1, 2, 5, 9]; + let v: Vec<_> = IntoIterator::into_iter(arr.clone()).collect(); + assert_eq!(&arr[..], &v[..]); +} + +#[test] +fn iterator_rev_collect() { + let arr = [0, 1, 2, 5, 9]; + let v: Vec<_> = IntoIterator::into_iter(arr.clone()).rev().collect(); + assert_eq!(&v[..], &[9, 5, 2, 1, 0]); +} + +#[test] +fn iterator_nth() { + let v = [0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(IntoIterator::into_iter(v.clone()).nth(i).unwrap(), v[i]); + } + assert_eq!(IntoIterator::into_iter(v.clone()).nth(v.len()), None); + + let mut iter = IntoIterator::into_iter(v); + assert_eq!(iter.nth(2).unwrap(), v[2]); + assert_eq!(iter.nth(1).unwrap(), v[4]); +} + +#[test] +fn iterator_last() { + let v = [0, 1, 2, 3, 4]; + assert_eq!(IntoIterator::into_iter(v).last().unwrap(), 4); + assert_eq!(IntoIterator::into_iter([0]).last().unwrap(), 0); + + let mut it = IntoIterator::into_iter([0, 9, 2, 4]); + assert_eq!(it.next_back(), Some(4)); + assert_eq!(it.last(), Some(2)); +} + +#[test] +fn iterator_clone() { + let mut it = IntoIterator::into_iter([0, 2, 4, 6, 8]); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let mut clone = it.clone(); + assert_eq!(it.next_back(), Some(6)); + assert_eq!(clone.next_back(), Some(6)); + assert_eq!(it.next_back(), Some(4)); + assert_eq!(clone.next_back(), Some(4)); + assert_eq!(it.next(), Some(2)); + assert_eq!(clone.next(), Some(2)); +} + +#[test] +fn iterator_fused() { + let mut it = IntoIterator::into_iter([0, 9, 2]); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(9)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); +} + +#[test] +fn iterator_len() { + let mut it = IntoIterator::into_iter([0, 1, 2, 5, 9]); + assert_eq!(it.size_hint(), (5, Some(5))); + assert_eq!(it.len(), 5); + assert_eq!(it.is_empty(), false); + + assert_eq!(it.next(), Some(0)); + assert_eq!(it.size_hint(), (4, Some(4))); + assert_eq!(it.len(), 4); + assert_eq!(it.is_empty(), false); + + assert_eq!(it.next_back(), Some(9)); + assert_eq!(it.size_hint(), (3, Some(3))); + assert_eq!(it.len(), 3); + assert_eq!(it.is_empty(), false); + + // Empty + let it = IntoIterator::into_iter([] as [String; 0]); + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.len(), 0); + assert_eq!(it.is_empty(), true); +} + +#[test] +fn iterator_count() { + let v = [0, 1, 2, 3, 4]; + assert_eq!(IntoIterator::into_iter(v.clone()).count(), 5); + + let mut iter2 = IntoIterator::into_iter(v); + iter2.next(); + iter2.next(); + assert_eq!(iter2.count(), 3); +} + +#[test] +fn iterator_flat_map() { + assert!((0..5).flat_map(|i| IntoIterator::into_iter([2 * i, 2 * i + 1])).eq(0..10)); +} + +#[test] +fn iterator_debug() { + let arr = [0, 1, 2, 5, 9]; + assert_eq!(format!("{:?}", IntoIterator::into_iter(arr)), "IntoIter([0, 1, 2, 5, 9])",); +} + +#[test] +fn iterator_drops() { + use core::cell::Cell; + + // This test makes sure the correct number of elements are dropped. The `R` + // type is just a reference to a `Cell` that is incremented when an `R` is + // dropped. + + #[derive(Clone)] + struct Foo<'a>(&'a Cell); + + impl Drop for Foo<'_> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + fn five(i: &Cell) -> [Foo<'_>; 5] { + // This is somewhat verbose because `Foo` does not implement `Copy` + // since it implements `Drop`. Consequently, we cannot write + // `[Foo(i); 5]`. + [Foo(i), Foo(i), Foo(i), Foo(i), Foo(i)] + } + + // Simple: drop new iterator. + let i = Cell::new(0); + { + IntoIterator::into_iter(five(&i)); + } + assert_eq!(i.get(), 5); + + // Call `next()` once. + let i = Cell::new(0); + { + let mut iter = IntoIterator::into_iter(five(&i)); + let _x = iter.next(); + assert_eq!(i.get(), 0); + assert_eq!(iter.count(), 4); + assert_eq!(i.get(), 4); + } + assert_eq!(i.get(), 5); + + // Check `clone` and calling `next`/`next_back`. + let i = Cell::new(0); + { + let mut iter = IntoIterator::into_iter(five(&i)); + iter.next(); + assert_eq!(i.get(), 1); + iter.next_back(); + assert_eq!(i.get(), 2); + + let mut clone = iter.clone(); + assert_eq!(i.get(), 2); + + iter.next(); + assert_eq!(i.get(), 3); + + clone.next(); + assert_eq!(i.get(), 4); + + assert_eq!(clone.count(), 2); + assert_eq!(i.get(), 6); + } + assert_eq!(i.get(), 8); + + // Check via `nth`. + let i = Cell::new(0); + { + let mut iter = IntoIterator::into_iter(five(&i)); + let _x = iter.nth(2); + assert_eq!(i.get(), 2); + let _y = iter.last(); + assert_eq!(i.get(), 3); + } + assert_eq!(i.get(), 5); + + // Check every element. + let i = Cell::new(0); + for (index, _x) in IntoIterator::into_iter(five(&i)).enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + for (index, _x) in IntoIterator::into_iter(five(&i)).rev().enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn array_default_impl_avoids_leaks_on_panic() { + use core::sync::atomic::AtomicUsize; + use core::sync::atomic::Ordering::Relaxed; + static COUNTER: AtomicUsize = AtomicUsize::new(0); + #[derive(Debug)] + struct Bomb(#[allow(dead_code)] usize); + + impl Default for Bomb { + fn default() -> Bomb { + if COUNTER.load(Relaxed) == 3 { + panic!("bomb limit exceeded"); + } + + COUNTER.fetch_add(1, Relaxed); + Bomb(COUNTER.load(Relaxed)) + } + } + + impl Drop for Bomb { + fn drop(&mut self) { + COUNTER.fetch_sub(1, Relaxed); + } + } + + let res = std::panic::catch_unwind(|| <[Bomb; 5]>::default()); + let panic_msg = match res { + Ok(_) => unreachable!(), + Err(p) => p.downcast::<&'static str>().unwrap(), + }; + assert_eq!(*panic_msg, "bomb limit exceeded"); + // check that all bombs are successfully dropped + assert_eq!(COUNTER.load(Relaxed), 0); +} + +#[test] +fn empty_array_is_always_default() { + struct DoesNotImplDefault; + + let _arr = <[DoesNotImplDefault; 0]>::default(); +} + +#[test] +fn array_map() { + let a = [1, 2, 3]; + let b = a.map(|v| v + 1); + assert_eq!(b, [2, 3, 4]); + + let a = [1u8, 2, 3]; + let b = a.map(|v| v as u64); + assert_eq!(b, [1, 2, 3]); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn array_map_drop_safety() { + static DROPPED: AtomicUsize = AtomicUsize::new(0); + struct DropCounter; + impl Drop for DropCounter { + fn drop(&mut self) { + DROPPED.fetch_add(1, Ordering::SeqCst); + } + } + + let num_to_create = 5; + let success = std::panic::catch_unwind(|| { + let items = [0; 10]; + let mut nth = 0; + items.map(|_| { + assert!(nth < num_to_create); + nth += 1; + DropCounter + }); + }); + assert!(success.is_err()); + assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create); +} + +#[test] +fn cell_allows_array_cycle() { + use core::cell::Cell; + + #[derive(Debug)] + struct B<'a> { + a: [Cell>>; 2], + } + + impl<'a> B<'a> { + fn new() -> B<'a> { + B { a: [Cell::new(None), Cell::new(None)] } + } + } + + let b1 = B::new(); + let b2 = B::new(); + let b3 = B::new(); + + b1.a[0].set(Some(&b2)); + b1.a[1].set(Some(&b3)); + + b2.a[0].set(Some(&b2)); + b2.a[1].set(Some(&b3)); + + b3.a[0].set(Some(&b1)); + b3.a[1].set(Some(&b2)); +} + +#[test] +fn array_from_fn() { + let array = core::array::from_fn(|idx| idx); + assert_eq!(array, [0, 1, 2, 3, 4]); +} + +#[test] +fn array_try_from_fn() { + #[derive(Debug, PartialEq)] + enum SomeError { + Foo, + } + + let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i)); + assert_eq!(array, Ok([0, 1, 2, 3, 4])); + + let another_array = core::array::try_from_fn::, 2, _>(|_| Err(SomeError::Foo)); + assert_eq!(another_array, Err(SomeError::Foo)); +} + +#[cfg(not(panic = "abort"))] +#[test] +fn array_try_from_fn_drops_inserted_elements_on_err() { + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + + struct CountDrop; + impl Drop for CountDrop { + fn drop(&mut self) { + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + + let _ = catch_unwind_silent(move || { + let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| { + if idx == 2 { + return Err(()); + } + Ok(CountDrop) + }); + }); + + assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2); +} + +#[cfg(not(panic = "abort"))] +#[test] +fn array_try_from_fn_drops_inserted_elements_on_panic() { + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); + + struct CountDrop; + impl Drop for CountDrop { + fn drop(&mut self) { + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + + let _ = catch_unwind_silent(move || { + let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| { + if idx == 2 { + panic!("peek a boo"); + } + Ok(CountDrop) + }); + }); + + assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2); +} + +#[cfg(not(panic = "abort"))] +// https://stackoverflow.com/a/59211505 +fn catch_unwind_silent(f: F) -> std::thread::Result +where + F: FnOnce() -> R + core::panic::UnwindSafe, +{ + let prev_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(|_| {})); + let result = std::panic::catch_unwind(f); + std::panic::set_hook(prev_hook); + result +} + +#[test] +fn array_split_array_mut() { + let mut v = [1, 2, 3, 4, 5, 6]; + + { + let (left, right) = v.split_array_mut::<0>(); + assert_eq!(left, &mut []); + assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); + } + + { + let (left, right) = v.split_array_mut::<6>(); + assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); + assert_eq!(right, &mut []); + } +} + +#[test] +fn array_rsplit_array_mut() { + let mut v = [1, 2, 3, 4, 5, 6]; + + { + let (left, right) = v.rsplit_array_mut::<0>(); + assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); + assert_eq!(right, &mut []); + } + + { + let (left, right) = v.rsplit_array_mut::<6>(); + assert_eq!(left, &mut []); + assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); + } +} + +#[should_panic] +#[test] +fn array_split_array_ref_out_of_bounds() { + let v = [1, 2, 3, 4, 5, 6]; + + v.split_array_ref::<7>(); +} + +#[should_panic] +#[test] +fn array_split_array_mut_out_of_bounds() { + let mut v = [1, 2, 3, 4, 5, 6]; + + v.split_array_mut::<7>(); +} + +#[should_panic] +#[test] +fn array_rsplit_array_ref_out_of_bounds() { + let v = [1, 2, 3, 4, 5, 6]; + + v.rsplit_array_ref::<7>(); +} + +#[should_panic] +#[test] +fn array_rsplit_array_mut_out_of_bounds() { + let mut v = [1, 2, 3, 4, 5, 6]; + + v.rsplit_array_mut::<7>(); +} + +#[test] +fn array_intoiter_advance_by() { + use std::cell::Cell; + struct DropCounter<'a>(usize, &'a Cell); + impl Drop for DropCounter<'_> { + fn drop(&mut self) { + let x = self.1.get(); + self.1.set(x + 1); + } + } + + let counter = Cell::new(0); + let a: [_; 100] = std::array::from_fn(|i| DropCounter(i, &counter)); + let mut it = IntoIterator::into_iter(a); + + let r = it.advance_by(1); + assert_eq!(r, Ok(())); + assert_eq!(it.len(), 99); + assert_eq!(counter.get(), 1); + + let r = it.advance_by(0); + assert_eq!(r, Ok(())); + assert_eq!(it.len(), 99); + assert_eq!(counter.get(), 1); + + let r = it.advance_by(11); + assert_eq!(r, Ok(())); + assert_eq!(it.len(), 88); + assert_eq!(counter.get(), 12); + + let x = it.next(); + assert_eq!(x.as_ref().map(|x| x.0), Some(12)); + assert_eq!(it.len(), 87); + assert_eq!(counter.get(), 12); + drop(x); + assert_eq!(counter.get(), 13); + + let r = it.advance_by(123456); + assert_eq!(r, Err(NonZero::new(123456 - 87).unwrap())); + assert_eq!(it.len(), 0); + assert_eq!(counter.get(), 100); + + let r = it.advance_by(0); + assert_eq!(r, Ok(())); + assert_eq!(it.len(), 0); + assert_eq!(counter.get(), 100); + + let r = it.advance_by(10); + assert_eq!(r, Err(NonZero::new(10).unwrap())); + assert_eq!(it.len(), 0); + assert_eq!(counter.get(), 100); +} + +#[test] +fn array_intoiter_advance_back_by() { + use std::cell::Cell; + struct DropCounter<'a>(usize, &'a Cell); + impl Drop for DropCounter<'_> { + fn drop(&mut self) { + let x = self.1.get(); + self.1.set(x + 1); + } + } + + let counter = Cell::new(0); + let a: [_; 100] = std::array::from_fn(|i| DropCounter(i, &counter)); + let mut it = IntoIterator::into_iter(a); + + let r = it.advance_back_by(1); + assert_eq!(r, Ok(())); + assert_eq!(it.len(), 99); + assert_eq!(counter.get(), 1); + + let r = it.advance_back_by(0); + assert_eq!(r, Ok(())); + assert_eq!(it.len(), 99); + assert_eq!(counter.get(), 1); + + let r = it.advance_back_by(11); + assert_eq!(r, Ok(())); + assert_eq!(it.len(), 88); + assert_eq!(counter.get(), 12); + + let x = it.next_back(); + assert_eq!(x.as_ref().map(|x| x.0), Some(87)); + assert_eq!(it.len(), 87); + assert_eq!(counter.get(), 12); + drop(x); + assert_eq!(counter.get(), 13); + + let r = it.advance_back_by(123456); + assert_eq!(r, Err(NonZero::new(123456 - 87).unwrap())); + assert_eq!(it.len(), 0); + assert_eq!(counter.get(), 100); + + let r = it.advance_back_by(0); + assert_eq!(r, Ok(())); + assert_eq!(it.len(), 0); + assert_eq!(counter.get(), 100); + + let r = it.advance_back_by(10); + assert_eq!(r, Err(NonZero::new(10).unwrap())); + assert_eq!(it.len(), 0); + assert_eq!(counter.get(), 100); +} + +#[test] +fn array_mixed_equality_integers() { + let array3: [i32; 3] = [1, 2, 3]; + let array3b: [i32; 3] = [3, 2, 1]; + let array4: [i32; 4] = [1, 2, 3, 4]; + + let slice3: &[i32] = &{ array3 }; + let slice3b: &[i32] = &{ array3b }; + let slice4: &[i32] = &{ array4 }; + assert!(array3 == slice3); + assert!(array3 != slice3b); + assert!(array3 != slice4); + assert!(slice3 == array3); + assert!(slice3b != array3); + assert!(slice4 != array3); + + let mut3: &mut [i32] = &mut { array3 }; + let mut3b: &mut [i32] = &mut { array3b }; + let mut4: &mut [i32] = &mut { array4 }; + assert!(array3 == mut3); + assert!(array3 != mut3b); + assert!(array3 != mut4); + assert!(mut3 == array3); + assert!(mut3b != array3); + assert!(mut4 != array3); +} + +#[test] +fn array_mixed_equality_nans() { + let array3: [f32; 3] = [1.0, std::f32::NAN, 3.0]; + + let slice3: &[f32] = &{ array3 }; + assert!(!(array3 == slice3)); + assert!(array3 != slice3); + assert!(!(slice3 == array3)); + assert!(slice3 != array3); + + let mut3: &mut [f32] = &mut { array3 }; + assert!(!(array3 == mut3)); + assert!(array3 != mut3); + assert!(!(mut3 == array3)); + assert!(mut3 != array3); +} + +#[test] +fn array_into_iter_fold() { + // Strings to help Miri catch if we double-free or something + let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()]; + let mut s = "s".to_string(); + a.into_iter().for_each(|b| s += &b); + assert_eq!(s, "sAaBbCc"); + + let a = [1, 2, 3, 4, 5, 6]; + let mut it = a.into_iter(); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.advance_back_by(2), Ok(())); + let s = it.fold(10, |a, b| 10 * a + b); + assert_eq!(s, 10234); +} + +#[test] +fn array_into_iter_rfold() { + // Strings to help Miri catch if we double-free or something + let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()]; + let mut s = "s".to_string(); + a.into_iter().rev().for_each(|b| s += &b); + assert_eq!(s, "sCcBbAa"); + + let a = [1, 2, 3, 4, 5, 6]; + let mut it = a.into_iter(); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.advance_back_by(2), Ok(())); + let s = it.rfold(10, |a, b| 10 * a + b); + assert_eq!(s, 10432); +} + +#[cfg(not(panic = "abort"))] +#[test] +fn array_map_drops_unmapped_elements_on_panic() { + struct DropCounter<'a>(usize, &'a AtomicUsize); + impl Drop for DropCounter<'_> { + fn drop(&mut self) { + self.1.fetch_add(1, Ordering::SeqCst); + } + } + + const MAX: usize = 11; + for panic_after in 0..MAX { + let counter = AtomicUsize::new(0); + let a = array::from_fn::<_, 11, _>(|i| DropCounter(i, &counter)); + let success = std::panic::catch_unwind(|| { + let _ = a.map(|x| { + assert!(x.0 < panic_after); + assert_eq!(counter.load(Ordering::SeqCst), x.0); + }); + }); + assert!(success.is_err()); + assert_eq!(counter.load(Ordering::SeqCst), MAX); + } +} diff --git a/library/coretests/tests/ascii.rs b/library/coretests/tests/ascii.rs new file mode 100644 index 00000000000..ce09ee507f1 --- /dev/null +++ b/library/coretests/tests/ascii.rs @@ -0,0 +1,507 @@ +use core::char::from_u32; + +#[test] +fn test_is_ascii() { + assert!(b"".is_ascii()); + assert!(b"banana\0\x7F".is_ascii()); + assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); + assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); + assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); + assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); + + assert!("".is_ascii()); + assert!("banana\0\u{7F}".is_ascii()); + assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); +} + +#[test] +fn test_to_ascii_uppercase() { + assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); + assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); + + for i in 0..501 { + let upper = + if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } else { i }; + assert_eq!( + (from_u32(i).unwrap()).to_string().to_ascii_uppercase(), + (from_u32(upper).unwrap()).to_string() + ); + } +} + +#[test] +fn test_to_ascii_lowercase() { + assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); + // Dotted capital I, Kelvin sign, Sharp S. + assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); + + for i in 0..501 { + let lower = + if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i }; + assert_eq!( + (from_u32(i).unwrap()).to_string().to_ascii_lowercase(), + (from_u32(lower).unwrap()).to_string() + ); + } +} + +#[test] +fn test_make_ascii_lower_case() { + macro_rules! test { + ($from: expr, $to: expr) => {{ + let mut x = $from; + x.make_ascii_lowercase(); + assert_eq!(x, $to); + }}; + } + test!(b'A', b'a'); + test!(b'a', b'a'); + test!(b'!', b'!'); + test!('A', 'a'); + test!('À', 'À'); + test!('a', 'a'); + test!('!', '!'); + test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); + test!("HİKß".to_string(), "hİKß"); +} + +#[test] +fn test_make_ascii_upper_case() { + macro_rules! test { + ($from: expr, $to: expr) => {{ + let mut x = $from; + x.make_ascii_uppercase(); + assert_eq!(x, $to); + }}; + } + test!(b'a', b'A'); + test!(b'A', b'A'); + test!(b'!', b'!'); + test!('a', 'A'); + test!('à', 'à'); + test!('A', 'A'); + test!('!', '!'); + test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); + test!("hıKß".to_string(), "HıKß"); + + let mut x = "Hello".to_string(); + x[..3].make_ascii_uppercase(); // Test IndexMut on String. + assert_eq!(x, "HELlo") +} + +#[test] +fn test_eq_ignore_ascii_case() { + assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); + assert!(!"Ürl".eq_ignore_ascii_case("ürl")); + // Dotted capital I, Kelvin sign, Sharp S. + assert!("HİKß".eq_ignore_ascii_case("hİKß")); + assert!(!"İ".eq_ignore_ascii_case("i")); + assert!(!"K".eq_ignore_ascii_case("k")); + assert!(!"ß".eq_ignore_ascii_case("s")); + + for i in 0..501 { + let lower = + if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i }; + assert!( + (from_u32(i).unwrap()) + .to_string() + .eq_ignore_ascii_case(&from_u32(lower).unwrap().to_string()) + ); + } +} + +#[test] +fn inference_works() { + let x = "a".to_string(); + let _ = x.eq_ignore_ascii_case("A"); +} + +// Shorthands used by the is_ascii_* tests. +macro_rules! assert_all { + ($what:ident, $($str:tt),+) => {{ + $( + for b in $str.chars() { + if !b.$what() { + panic!("expected {}({}) but it isn't", + stringify!($what), b); + } + } + for b in $str.as_bytes().iter() { + if !b.$what() { + panic!("expected {}(0x{:02x})) but it isn't", + stringify!($what), b); + } + } + )+ + }}; + ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) +} +macro_rules! assert_none { + ($what:ident, $($str:tt),+) => {{ + $( + for b in $str.chars() { + if b.$what() { + panic!("expected not-{}({}) but it is", + stringify!($what), b); + } + } + for b in $str.as_bytes().iter() { + if b.$what() { + panic!("expected not-{}(0x{:02x})) but it is", + stringify!($what), b); + } + } + )+ + }}; + ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) +} + +#[test] +fn test_is_ascii_alphabetic() { + assert_all!( + is_ascii_alphabetic, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + ); + assert_none!( + is_ascii_alphabetic, + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_uppercase() { + assert_all!(is_ascii_uppercase, "", "ABCDEFGHIJKLMNOQPRSTUVWXYZ",); + assert_none!( + is_ascii_uppercase, + "abcdefghijklmnopqrstuvwxyz", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_lowercase() { + assert_all!(is_ascii_lowercase, "abcdefghijklmnopqrstuvwxyz",); + assert_none!( + is_ascii_lowercase, + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_alphanumeric() { + assert_all!( + is_ascii_alphanumeric, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + ); + assert_none!( + is_ascii_alphanumeric, + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_digit() { + assert_all!(is_ascii_digit, "", "0123456789",); + assert_none!( + is_ascii_digit, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_octdigit() { + assert_all!(is_ascii_octdigit, "", "01234567"); + assert_none!( + is_ascii_octdigit, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_hexdigit() { + assert_all!(is_ascii_hexdigit, "", "0123456789", "abcdefABCDEF",); + assert_none!( + is_ascii_hexdigit, + "ghijklmnopqrstuvwxyz", + "GHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_punctuation() { + assert_all!(is_ascii_punctuation, "", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",); + assert_none!( + is_ascii_punctuation, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_graphic() { + assert_all!( + is_ascii_graphic, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ); + assert_none!( + is_ascii_graphic, + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_whitespace() { + assert_all!(is_ascii_whitespace, "", " \t\n\x0c\r",); + assert_none!( + is_ascii_whitespace, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x0b\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_control() { + assert_all!( + is_ascii_control, + "", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + assert_none!( + is_ascii_control, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " ", + ); +} + +// `is_ascii` does a good amount of pointer manipulation and has +// alignment-dependent computation. This is all sanity-checked via +// `debug_assert!`s, so we test various sizes/alignments thoroughly versus an +// "obviously correct" baseline function. +#[test] +fn test_is_ascii_align_size_thoroughly() { + // The "obviously-correct" baseline mentioned above. + fn is_ascii_baseline(s: &[u8]) -> bool { + s.iter().all(|b| b.is_ascii()) + } + + // Helper to repeat `l` copies of `b0` followed by `l` copies of `b1`. + fn repeat_concat(b0: u8, b1: u8, l: usize) -> Vec { + use core::iter::repeat; + repeat(b0).take(l).chain(repeat(b1).take(l)).collect() + } + + // Miri is too slow + let iter = if cfg!(miri) { 0..20 } else { 0..100 }; + + for i in iter { + #[cfg(not(miri))] + let cases = &[ + b"a".repeat(i), + b"\0".repeat(i), + b"\x7f".repeat(i), + b"\x80".repeat(i), + b"\xff".repeat(i), + repeat_concat(b'a', 0x80u8, i), + repeat_concat(0x80u8, b'a', i), + ]; + + #[cfg(miri)] + let cases = &[b"a".repeat(i), b"\x80".repeat(i), repeat_concat(b'a', 0x80u8, i)]; + + for case in cases { + for pos in 0..=case.len() { + // Potentially misaligned head + let prefix = &case[pos..]; + assert_eq!(is_ascii_baseline(prefix), prefix.is_ascii(),); + + // Potentially misaligned tail + let suffix = &case[..case.len() - pos]; + + assert_eq!(is_ascii_baseline(suffix), suffix.is_ascii(),); + + // Both head and tail are potentially misaligned + let mid = &case[(pos / 2)..(case.len() - (pos / 2))]; + assert_eq!(is_ascii_baseline(mid), mid.is_ascii(),); + } + } + } +} + +#[test] +fn ascii_const() { + // test that the `is_ascii` methods of `char` and `u8` are usable in a const context + + const CHAR_IS_ASCII: bool = 'a'.is_ascii(); + assert!(CHAR_IS_ASCII); + + const BYTE_IS_ASCII: bool = 97u8.is_ascii(); + assert!(BYTE_IS_ASCII); +} + +#[test] +fn ascii_ctype_const() { + macro_rules! suite { + ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { + $( + mod $fn { + const CHAR_A_LOWER: bool = 'a'.$fn(); + const CHAR_A_UPPER: bool = 'A'.$fn(); + const CHAR_NINE: bool = '9'.$fn(); + const CHAR_DOT: bool = '.'.$fn(); + const CHAR_SPACE: bool = ' '.$fn(); + + const U8_A_LOWER: bool = b'a'.$fn(); + const U8_A_UPPER: bool = b'A'.$fn(); + const U8_NINE: bool = b'9'.$fn(); + const U8_DOT: bool = b'.'.$fn(); + const U8_SPACE: bool = b' '.$fn(); + + pub fn run() { + assert_eq!(CHAR_A_LOWER, $a); + assert_eq!(CHAR_A_UPPER, $A); + assert_eq!(CHAR_NINE, $nine); + assert_eq!(CHAR_DOT, $dot); + assert_eq!(CHAR_SPACE, $space); + + assert_eq!(U8_A_LOWER, $a); + assert_eq!(U8_A_UPPER, $A); + assert_eq!(U8_NINE, $nine); + assert_eq!(U8_DOT, $dot); + assert_eq!(U8_SPACE, $space); + } + } + )* + + $( $fn::run(); )* + } + } + + suite! { + // 'a' 'A' '9' '.' ' ' + is_ascii_alphabetic => [true, true, false, false, false]; + is_ascii_uppercase => [false, true, false, false, false]; + is_ascii_lowercase => [true, false, false, false, false]; + is_ascii_alphanumeric => [true, true, true, false, false]; + is_ascii_digit => [false, false, true, false, false]; + is_ascii_octdigit => [false, false, false, false, false]; + is_ascii_hexdigit => [true, true, true, false, false]; + is_ascii_punctuation => [false, false, false, true, false]; + is_ascii_graphic => [true, true, true, true, false]; + is_ascii_whitespace => [false, false, false, false, true]; + is_ascii_control => [false, false, false, false, false]; + } +} + +#[test] +fn test_escape_ascii() { + let mut buf = [0u8; 0x1F + 7]; // 0..=0x1F plus two quotes, slash, \x7F, \x80, \xFF + for idx in 0..=0x1F { + buf[idx] = idx as u8; + } + buf[0x20] = b'\''; + buf[0x21] = b'"'; + buf[0x22] = b'\\'; + buf[0x23] = 0x7F; + buf[0x24] = 0x80; + buf[0x25] = 0xff; + assert_eq!( + buf.escape_ascii().to_string(), + r#"\x00\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\'\"\\\x7f\x80\xff"# + ); +} + +#[test] +fn test_escape_ascii_iter() { + let mut it = b"\0fastpath\xffremainder\xff".escape_ascii(); + let _ = it.advance_by(4); + let _ = it.advance_back_by(4); + assert_eq!(it.to_string(), r#"fastpath\xffremainder"#); +} diff --git a/library/coretests/tests/ascii_char.rs b/library/coretests/tests/ascii_char.rs new file mode 100644 index 00000000000..75b5fd4b9e6 --- /dev/null +++ b/library/coretests/tests/ascii_char.rs @@ -0,0 +1,28 @@ +use core::ascii::Char; +use core::fmt::Write; + +/// Tests Display implementation for ascii::Char. +#[test] +fn test_display() { + let want = (0..128u8).map(|b| b as char).collect::(); + let mut got = String::with_capacity(128); + for byte in 0..128 { + write!(&mut got, "{}", Char::from_u8(byte).unwrap()).unwrap(); + } + assert_eq!(want, got); +} + +/// Tests Debug implementation for ascii::Char. +#[test] +fn test_debug_control() { + for byte in 0..128u8 { + let mut want = format!("{:?}", byte as char); + // `char` uses `'\u{#}'` representation where ascii::char uses `'\x##'`. + // Transform former into the latter. + if let Some(rest) = want.strip_prefix("'\\u{") { + want = format!("'\\x{:0>2}'", rest.strip_suffix("}'").unwrap()); + } + let chr = core::ascii::Char::from_u8(byte).unwrap(); + assert_eq!(want, format!("{chr:?}"), "byte: {byte}"); + } +} diff --git a/library/coretests/tests/asserting.rs b/library/coretests/tests/asserting.rs new file mode 100644 index 00000000000..1d9670886eb --- /dev/null +++ b/library/coretests/tests/asserting.rs @@ -0,0 +1,37 @@ +use core::asserting::{Capture, TryCaptureGeneric, TryCapturePrintable, Wrapper}; + +macro_rules! test { + ($test_name:ident, $elem:expr, $captured_elem:expr, $output:literal) => { + #[test] + fn $test_name() { + let elem = $elem; + let mut capture = Capture::new(); + assert!(capture.elem == None); + (&Wrapper(&elem)).try_capture(&mut capture); + assert!(capture.elem == $captured_elem); + assert_eq!(format!("{:?}", capture), $output); + } + }; +} + +#[derive(Debug, PartialEq)] +struct NoCopy; + +#[derive(PartialEq)] +struct NoCopyNoDebug; + +#[derive(Clone, Copy, PartialEq)] +struct NoDebug; + +test!( + capture_with_non_copyable_and_non_debuggable_elem_has_correct_params, + NoCopyNoDebug, + None, + "N/A" +); + +test!(capture_with_non_copyable_elem_has_correct_params, NoCopy, None, "N/A"); + +test!(capture_with_non_debuggable_elem_has_correct_params, NoDebug, None, "N/A"); + +test!(capture_with_copyable_and_debuggable_elem_has_correct_params, 1i32, Some(1i32), "1"); diff --git a/library/coretests/tests/async_iter/mod.rs b/library/coretests/tests/async_iter/mod.rs new file mode 100644 index 00000000000..4f425d7286d --- /dev/null +++ b/library/coretests/tests/async_iter/mod.rs @@ -0,0 +1,16 @@ +use core::async_iter::{self, AsyncIterator, IntoAsyncIterator}; +use core::pin::pin; +use core::task::Poll; + +#[test] +fn into_async_iter() { + let async_iter = async_iter::from_iter(0..3); + let mut async_iter = pin!(async_iter.into_async_iter()); + + let mut cx = &mut core::task::Context::from_waker(core::task::Waker::noop()); + + assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(0))); + assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(1))); + assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(Some(2))); + assert_eq!(async_iter.as_mut().poll_next(&mut cx), Poll::Ready(None)); +} diff --git a/library/coretests/tests/atomic.rs b/library/coretests/tests/atomic.rs new file mode 100644 index 00000000000..0ffba538b20 --- /dev/null +++ b/library/coretests/tests/atomic.rs @@ -0,0 +1,318 @@ +use core::sync::atomic::Ordering::SeqCst; +use core::sync::atomic::*; + +#[test] +fn bool_() { + let a = AtomicBool::new(false); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false)); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Err(true)); + + a.store(false, SeqCst); + assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false)); +} + +#[test] +fn bool_and() { + let a = AtomicBool::new(true); + assert_eq!(a.fetch_and(false, SeqCst), true); + assert_eq!(a.load(SeqCst), false); +} + +#[test] +fn bool_nand() { + let a = AtomicBool::new(false); + assert_eq!(a.fetch_nand(false, SeqCst), false); + assert_eq!(a.load(SeqCst), true); + assert_eq!(a.fetch_nand(false, SeqCst), true); + assert_eq!(a.load(SeqCst), true); + assert_eq!(a.fetch_nand(true, SeqCst), true); + assert_eq!(a.load(SeqCst), false); + assert_eq!(a.fetch_nand(true, SeqCst), false); + assert_eq!(a.load(SeqCst), true); +} + +#[test] +fn uint_and() { + let x = AtomicUsize::new(0xf731); + assert_eq!(x.fetch_and(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731 & 0x137f); +} + +#[test] +fn uint_nand() { + let x = AtomicUsize::new(0xf731); + assert_eq!(x.fetch_nand(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), !(0xf731 & 0x137f)); +} + +#[test] +fn uint_or() { + let x = AtomicUsize::new(0xf731); + assert_eq!(x.fetch_or(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731 | 0x137f); +} + +#[test] +fn uint_xor() { + let x = AtomicUsize::new(0xf731); + assert_eq!(x.fetch_xor(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn uint_min() { + let x = AtomicUsize::new(0xf731); + assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0x137f); + assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f); + assert_eq!(x.load(SeqCst), 0x137f); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn uint_max() { + let x = AtomicUsize::new(0x137f); + assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); + assert_eq!(x.load(SeqCst), 0xf731); + assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731); +} + +#[test] +fn int_and() { + let x = AtomicIsize::new(0xf731); + assert_eq!(x.fetch_and(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731 & 0x137f); +} + +#[test] +fn int_nand() { + let x = AtomicIsize::new(0xf731); + assert_eq!(x.fetch_nand(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), !(0xf731 & 0x137f)); +} + +#[test] +fn int_or() { + let x = AtomicIsize::new(0xf731); + assert_eq!(x.fetch_or(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731 | 0x137f); +} + +#[test] +fn int_xor() { + let x = AtomicIsize::new(0xf731); + assert_eq!(x.fetch_xor(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn int_min() { + let x = AtomicIsize::new(0xf731); + assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0x137f); + assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f); + assert_eq!(x.load(SeqCst), 0x137f); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn int_max() { + let x = AtomicIsize::new(0x137f); + assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f); + assert_eq!(x.load(SeqCst), 0xf731); + assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731); + assert_eq!(x.load(SeqCst), 0xf731); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn ptr_add_null() { + let atom = AtomicPtr::::new(core::ptr::null_mut()); + assert_eq!(atom.fetch_ptr_add(1, SeqCst).addr(), 0); + assert_eq!(atom.load(SeqCst).addr(), 8); + + assert_eq!(atom.fetch_byte_add(1, SeqCst).addr(), 8); + assert_eq!(atom.load(SeqCst).addr(), 9); + + assert_eq!(atom.fetch_ptr_sub(1, SeqCst).addr(), 9); + assert_eq!(atom.load(SeqCst).addr(), 1); + + assert_eq!(atom.fetch_byte_sub(1, SeqCst).addr(), 1); + assert_eq!(atom.load(SeqCst).addr(), 0); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn ptr_add_data() { + let num = 0i64; + let n = &num as *const i64 as *mut _; + let atom = AtomicPtr::::new(n); + assert_eq!(atom.fetch_ptr_add(1, SeqCst), n); + assert_eq!(atom.load(SeqCst), n.wrapping_add(1)); + + assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1)); + assert_eq!(atom.load(SeqCst), n); + let bytes_from_n = |b| n.wrapping_byte_add(b); + + assert_eq!(atom.fetch_byte_add(1, SeqCst), n); + assert_eq!(atom.load(SeqCst), bytes_from_n(1)); + + assert_eq!(atom.fetch_byte_add(5, SeqCst), bytes_from_n(1)); + assert_eq!(atom.load(SeqCst), bytes_from_n(6)); + + assert_eq!(atom.fetch_byte_sub(1, SeqCst), bytes_from_n(6)); + assert_eq!(atom.load(SeqCst), bytes_from_n(5)); + + assert_eq!(atom.fetch_byte_sub(5, SeqCst), bytes_from_n(5)); + assert_eq!(atom.load(SeqCst), n); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn ptr_bitops() { + let atom = AtomicPtr::::new(core::ptr::null_mut()); + assert_eq!(atom.fetch_or(0b0111, SeqCst).addr(), 0); + assert_eq!(atom.load(SeqCst).addr(), 0b0111); + + assert_eq!(atom.fetch_and(0b1101, SeqCst).addr(), 0b0111); + assert_eq!(atom.load(SeqCst).addr(), 0b0101); + + assert_eq!(atom.fetch_xor(0b1111, SeqCst).addr(), 0b0101); + assert_eq!(atom.load(SeqCst).addr(), 0b1010); +} + +#[test] +#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins +fn ptr_bitops_tagging() { + #[repr(align(16))] + struct Tagme(#[allow(dead_code)] u128); + + let tagme = Tagme(1000); + let ptr = &tagme as *const Tagme as *mut Tagme; + let atom: AtomicPtr = AtomicPtr::new(ptr); + + const MASK_TAG: usize = 0b1111; + const MASK_PTR: usize = !MASK_TAG; + + assert_eq!(ptr.addr() & MASK_TAG, 0); + + assert_eq!(atom.fetch_or(0b0111, SeqCst), ptr); + assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b111)); + + assert_eq!(atom.fetch_and(MASK_PTR | 0b0010, SeqCst), ptr.map_addr(|a| a | 0b111)); + assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b0010)); + + assert_eq!(atom.fetch_xor(0b1011, SeqCst), ptr.map_addr(|a| a | 0b0010)); + assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b1001)); + + assert_eq!(atom.fetch_and(MASK_PTR, SeqCst), ptr.map_addr(|a| a | 0b1001)); + assert_eq!(atom.load(SeqCst), ptr); +} + +static S_FALSE: AtomicBool = AtomicBool::new(false); +static S_TRUE: AtomicBool = AtomicBool::new(true); +static S_INT: AtomicIsize = AtomicIsize::new(0); +static S_UINT: AtomicUsize = AtomicUsize::new(0); + +#[test] +fn static_init() { + // Note that we're not really testing the mutability here but it's important + // on Android at the moment (#49775) + assert!(!S_FALSE.swap(true, SeqCst)); + assert!(S_TRUE.swap(false, SeqCst)); + assert!(S_INT.fetch_add(1, SeqCst) == 0); + assert!(S_UINT.fetch_add(1, SeqCst) == 0); +} + +#[test] +// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +#[allow(static_mut_refs)] +fn atomic_access_bool() { + static mut ATOMIC: AtomicBool = AtomicBool::new(false); + + unsafe { + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.store(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_or(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_and(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.fetch_nand(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_xor(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + } +} + +#[test] +fn atomic_alignment() { + use std::mem::{align_of, size_of}; + + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::>(), size_of::>()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); +} + +#[test] +fn atomic_compare_exchange() { + use Ordering::*; + + static ATOMIC: AtomicIsize = AtomicIsize::new(0); + + ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); + ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); +} + +/* FIXME(#110395) +#[test] +fn atomic_const_from() { + const _ATOMIC_U8: AtomicU8 = AtomicU8::from(1); + const _ATOMIC_BOOL: AtomicBool = AtomicBool::from(true); + const _ATOMIC_PTR: AtomicPtr = AtomicPtr::from(core::ptr::null_mut()); +} +*/ diff --git a/library/coretests/tests/bool.rs b/library/coretests/tests/bool.rs new file mode 100644 index 00000000000..47f6459915b --- /dev/null +++ b/library/coretests/tests/bool.rs @@ -0,0 +1,107 @@ +use core::cmp::Ordering::{Equal, Greater, Less}; +use core::ops::{BitAnd, BitOr, BitXor}; + +#[test] +fn test_bool() { + assert_eq!(false.eq(&true), false); + assert_eq!(false == false, true); + assert_eq!(false != true, true); + assert_eq!(false.ne(&false), false); + + assert_eq!(false.bitand(false), false); + assert_eq!(true.bitand(false), false); + assert_eq!(false.bitand(true), false); + assert_eq!(true.bitand(true), true); + + assert_eq!(false & false, false); + assert_eq!(true & false, false); + assert_eq!(false & true, false); + assert_eq!(true & true, true); + + assert_eq!(false.bitor(false), false); + assert_eq!(true.bitor(false), true); + assert_eq!(false.bitor(true), true); + assert_eq!(true.bitor(true), true); + + assert_eq!(false | false, false); + assert_eq!(true | false, true); + assert_eq!(false | true, true); + assert_eq!(true | true, true); + + assert_eq!(false.bitxor(false), false); + assert_eq!(true.bitxor(false), true); + assert_eq!(false.bitxor(true), true); + assert_eq!(true.bitxor(true), false); + + assert_eq!(false ^ false, false); + assert_eq!(true ^ false, true); + assert_eq!(false ^ true, true); + assert_eq!(true ^ true, false); + + assert_eq!(!true, false); + assert_eq!(!false, true); + + let s = false.to_string(); + assert_eq!(s, "false"); + let s = true.to_string(); + assert_eq!(s, "true"); + + assert!(true > false); + assert!(!(false > true)); + + assert!(false < true); + assert!(!(true < false)); + + assert!(false <= false); + assert!(false >= false); + assert!(true <= true); + assert!(true >= true); + + assert!(false <= true); + assert!(!(false >= true)); + assert!(true >= false); + assert!(!(true <= false)); + + assert_eq!(true.cmp(&true), Equal); + assert_eq!(false.cmp(&false), Equal); + assert_eq!(true.cmp(&false), Greater); + assert_eq!(false.cmp(&true), Less); +} + +#[test] +pub fn test_bool_not() { + if !false { + assert!((true)); + } else { + assert!((false)); + } + if !true { + assert!((false)); + } else { + assert!((true)); + } +} + +#[test] +fn test_bool_to_option() { + assert_eq!(false.then_some(0), None); + assert_eq!(true.then_some(0), Some(0)); + assert_eq!(false.then(|| 0), None); + assert_eq!(true.then(|| 0), Some(0)); + + /* FIXME(#110395) + const fn zero() -> i32 { + 0 + } + + const A: Option = false.then_some(0); + const B: Option = true.then_some(0); + const C: Option = false.then(zero); + const D: Option = true.then(zero); + + assert_eq!(A, None); + assert_eq!(B, Some(0)); + assert_eq!(C, None); + assert_eq!(D, Some(0)); + */ +} diff --git a/library/coretests/tests/bstr.rs b/library/coretests/tests/bstr.rs new file mode 100644 index 00000000000..5fecd0a4084 --- /dev/null +++ b/library/coretests/tests/bstr.rs @@ -0,0 +1,54 @@ +#![feature(bstr)] + +use core::ByteStr; + +#[test] +fn test_debug() { + assert_eq!( + r#""\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff""#, + format!("{:?}", ByteStr::new(b"\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff")), + ); +} + +#[test] +fn test_display() { + let b1 = ByteStr::new("abc"); + let b2 = ByteStr::new(b"\xf0\x28\x8c\xbc"); + + assert_eq!(&format!("{b1}"), "abc"); + assert_eq!(&format!("{b2}"), "�(��"); + + assert_eq!(&format!("{b1:<7}!"), "abc !"); + assert_eq!(&format!("{b1:>7}!"), " abc!"); + assert_eq!(&format!("{b1:^7}!"), " abc !"); + assert_eq!(&format!("{b1:^6}!"), " abc !"); + assert_eq!(&format!("{b1:-<7}!"), "abc----!"); + assert_eq!(&format!("{b1:->7}!"), "----abc!"); + assert_eq!(&format!("{b1:-^7}!"), "--abc--!"); + assert_eq!(&format!("{b1:-^6}!"), "-abc--!"); + + assert_eq!(&format!("{b2:<7}!"), "�(�� !"); + assert_eq!(&format!("{b2:>7}!"), " �(��!"); + assert_eq!(&format!("{b2:^7}!"), " �(�� !"); + assert_eq!(&format!("{b2:^6}!"), " �(�� !"); + assert_eq!(&format!("{b2:-<7}!"), "�(��---!"); + assert_eq!(&format!("{b2:->7}!"), "---�(��!"); + assert_eq!(&format!("{b2:-^7}!"), "-�(��--!"); + assert_eq!(&format!("{b2:-^6}!"), "-�(��-!"); + + assert_eq!(&format!("{b1:<2}!"), "abc!"); + assert_eq!(&format!("{b1:>2}!"), "abc!"); + assert_eq!(&format!("{b1:^2}!"), "abc!"); + assert_eq!(&format!("{b1:-<2}!"), "abc!"); + assert_eq!(&format!("{b1:->2}!"), "abc!"); + assert_eq!(&format!("{b1:-^2}!"), "abc!"); + + assert_eq!(&format!("{b2:<3}!"), "�(��!"); + assert_eq!(&format!("{b2:>3}!"), "�(��!"); + assert_eq!(&format!("{b2:^3}!"), "�(��!"); + assert_eq!(&format!("{b2:^2}!"), "�(��!"); + assert_eq!(&format!("{b2:-<3}!"), "�(��!"); + assert_eq!(&format!("{b2:->3}!"), "�(��!"); + assert_eq!(&format!("{b2:-^3}!"), "�(��!"); + assert_eq!(&format!("{b2:-^2}!"), "�(��!"); +} diff --git a/library/coretests/tests/cell.rs b/library/coretests/tests/cell.rs new file mode 100644 index 00000000000..d6a401c2b4d --- /dev/null +++ b/library/coretests/tests/cell.rs @@ -0,0 +1,479 @@ +use core::cell::*; + +#[test] +fn smoketest_unsafe_cell() { + let mut x = UnsafeCell::new(10); + let ref_mut = &mut x; + unsafe { + // The asserts are repeated in order to ensure that `get()` + // is non-mutating. + assert_eq!(*ref_mut.get(), 10); + assert_eq!(*ref_mut.get(), 10); + *ref_mut.get_mut() += 5; + assert_eq!(*ref_mut.get(), 15); + assert_eq!(*ref_mut.get(), 15); + assert_eq!(x.into_inner(), 15); + } +} + +#[test] +fn unsafe_cell_raw_get() { + let x = UnsafeCell::new(10); + let ptr = &x as *const UnsafeCell; + unsafe { + // The asserts are repeated in order to ensure that `raw_get()` + // is non-mutating. + assert_eq!(*UnsafeCell::raw_get(ptr), 10); + assert_eq!(*UnsafeCell::raw_get(ptr), 10); + *UnsafeCell::raw_get(ptr) += 5; + assert_eq!(*UnsafeCell::raw_get(ptr), 15); + assert_eq!(*UnsafeCell::raw_get(ptr), 15); + assert_eq!(x.into_inner(), 15); + } +} + +#[test] +fn smoketest_cell() { + let x = Cell::new(10); + assert_eq!(x, Cell::new(10)); + assert_eq!(x.get(), 10); + x.set(20); + assert_eq!(x, Cell::new(20)); + assert_eq!(x.get(), 20); + + let y = Cell::new((30, 40)); + assert_eq!(y, Cell::new((30, 40))); + assert_eq!(y.get(), (30, 40)); +} + +#[test] +fn cell_update() { + let x = Cell::new(10); + + assert_eq!(x.update(|x| x + 5), 15); + assert_eq!(x.get(), 15); + + assert_eq!(x.update(|x| x / 3), 5); + assert_eq!(x.get(), 5); +} + +#[test] +fn cell_has_sensible_show() { + let x = Cell::new("foo bar"); + assert!(format!("{x:?}").contains(x.get())); + + x.set("baz qux"); + assert!(format!("{x:?}").contains(x.get())); +} + +#[test] +fn ref_and_refmut_have_sensible_show() { + let refcell = RefCell::new("foo"); + + let refcell_refmut = refcell.borrow_mut(); + assert_eq!(format!("{refcell_refmut}"), "foo"); // Display + assert!(format!("{refcell_refmut:?}").contains("foo")); // Debug + drop(refcell_refmut); + + let refcell_ref = refcell.borrow(); + assert_eq!(format!("{refcell_ref}"), "foo"); // Display + assert!(format!("{refcell_ref:?}").contains("foo")); // Debug + drop(refcell_ref); +} + +#[test] +fn double_imm_borrow() { + let x = RefCell::new(0); + let _b1 = x.borrow(); + x.borrow(); +} + +#[test] +fn no_mut_then_imm_borrow() { + let x = RefCell::new(0); + let _b1 = x.borrow_mut(); + assert!(x.try_borrow().is_err()); +} + +#[test] +fn no_imm_then_borrow_mut() { + let x = RefCell::new(0); + let _b1 = x.borrow(); + assert!(x.try_borrow_mut().is_err()); +} + +#[test] +fn no_double_borrow_mut() { + let x = RefCell::new(0); + assert!(x.try_borrow().is_ok()); + let _b1 = x.borrow_mut(); + assert!(x.try_borrow().is_err()); +} + +#[test] +fn imm_release_borrow_mut() { + let x = RefCell::new(0); + { + let _b1 = x.borrow(); + } + x.borrow_mut(); +} + +#[test] +fn mut_release_borrow_mut() { + let x = RefCell::new(0); + { + let _b1 = x.borrow_mut(); + } + x.borrow(); +} + +#[test] +fn double_borrow_single_release_no_borrow_mut() { + let x = RefCell::new(0); + let _b1 = x.borrow(); + { + let _b2 = x.borrow(); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); +} + +#[test] +#[should_panic] +fn discard_doesnt_unborrow() { + let x = RefCell::new(0); + let _b = x.borrow(); + let _ = _b; + let _b = x.borrow_mut(); +} + +#[test] +fn ref_clone_updates_flag() { + let x = RefCell::new(0); + { + let b1 = x.borrow(); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + { + let _b2 = Ref::clone(&b1); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); +} + +#[test] +fn ref_map_does_not_update_flag() { + let x = RefCell::new(Some(5)); + { + let b1: Ref<'_, Option> = x.borrow(); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + { + let b2: Ref<'_, u32> = Ref::map(b1, |o| o.as_ref().unwrap()); + assert_eq!(*b2, 5); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); +} + +#[test] +fn ref_map_split_updates_flag() { + let x = RefCell::new([1, 2]); + { + let b1 = x.borrow(); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + { + let (_b2, _b3) = Ref::map_split(b1, |slc| slc.split_at(1)); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + + { + let b1 = x.borrow_mut(); + assert!(x.try_borrow().is_err()); + assert!(x.try_borrow_mut().is_err()); + { + let (_b2, _b3) = RefMut::map_split(b1, |slc| slc.split_at_mut(1)); + assert!(x.try_borrow().is_err()); + assert!(x.try_borrow_mut().is_err()); + drop(_b2); + assert!(x.try_borrow().is_err()); + assert!(x.try_borrow_mut().is_err()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); +} + +#[test] +fn ref_map_split() { + let x = RefCell::new([1, 2]); + let (b1, b2) = Ref::map_split(x.borrow(), |slc| slc.split_at(1)); + assert_eq!(*b1, [1]); + assert_eq!(*b2, [2]); +} + +#[test] +fn ref_mut_map_split() { + let x = RefCell::new([1, 2]); + { + let (mut b1, mut b2) = RefMut::map_split(x.borrow_mut(), |slc| slc.split_at_mut(1)); + assert_eq!(*b1, [1]); + assert_eq!(*b2, [2]); + b1[0] = 2; + b2[0] = 1; + } + assert_eq!(*x.borrow(), [2, 1]); +} + +#[test] +fn ref_map_accessor() { + struct X(RefCell<(u32, char)>); + impl X { + fn accessor(&self) -> Ref<'_, u32> { + Ref::map(self.0.borrow(), |tuple| &tuple.0) + } + } + let x = X(RefCell::new((7, 'z'))); + let d: Ref<'_, u32> = x.accessor(); + assert_eq!(*d, 7); +} + +#[test] +fn ref_mut_map_accessor() { + struct X(RefCell<(u32, char)>); + impl X { + fn accessor(&self) -> RefMut<'_, u32> { + RefMut::map(self.0.borrow_mut(), |tuple| &mut tuple.0) + } + } + let x = X(RefCell::new((7, 'z'))); + { + let mut d: RefMut<'_, u32> = x.accessor(); + assert_eq!(*d, 7); + *d += 1; + } + assert_eq!(*x.0.borrow(), (8, 'z')); +} + +#[test] +fn as_ptr() { + let c1: Cell = Cell::new(0); + c1.set(1); + assert_eq!(1, unsafe { *c1.as_ptr() }); + + let c2: Cell = Cell::new(0); + unsafe { + *c2.as_ptr() = 1; + } + assert_eq!(1, c2.get()); + + let r1: RefCell = RefCell::new(0); + *r1.borrow_mut() = 1; + assert_eq!(1, unsafe { *r1.as_ptr() }); + + let r2: RefCell = RefCell::new(0); + unsafe { + *r2.as_ptr() = 1; + } + assert_eq!(1, *r2.borrow()); +} + +#[test] +fn cell_default() { + let cell: Cell = Default::default(); + assert_eq!(0, cell.get()); +} + +#[test] +fn cell_set() { + let cell = Cell::new(10); + cell.set(20); + assert_eq!(20, cell.get()); + + let cell = Cell::new("Hello".to_owned()); + cell.set("World".to_owned()); + assert_eq!("World".to_owned(), cell.into_inner()); +} + +#[test] +fn cell_replace() { + let cell = Cell::new(10); + assert_eq!(10, cell.replace(20)); + assert_eq!(20, cell.get()); + + let cell = Cell::new("Hello".to_owned()); + assert_eq!("Hello".to_owned(), cell.replace("World".to_owned())); + assert_eq!("World".to_owned(), cell.into_inner()); +} + +#[test] +fn cell_into_inner() { + let cell = Cell::new(10); + assert_eq!(10, cell.into_inner()); + + let cell = Cell::new("Hello world".to_owned()); + assert_eq!("Hello world".to_owned(), cell.into_inner()); +} + +#[test] +fn cell_exterior() { + #[derive(Copy, Clone)] + #[allow(dead_code)] + struct Point { + x: isize, + y: isize, + z: isize, + } + + fn f(p: &Cell) { + assert_eq!(p.get().z, 12); + p.set(Point { x: 10, y: 11, z: 13 }); + assert_eq!(p.get().z, 13); + } + + let a = Point { x: 10, y: 11, z: 12 }; + let b = &Cell::new(a); + assert_eq!(b.get().z, 12); + f(b); + assert_eq!(a.z, 12); + assert_eq!(b.get().z, 13); +} + +#[test] +fn cell_does_not_clone() { + #[derive(Copy)] + #[allow(dead_code)] + struct Foo { + x: isize, + } + + impl Clone for Foo { + fn clone(&self) -> Foo { + // Using Cell in any way should never cause clone() to be + // invoked -- after all, that would permit evil user code to + // abuse `Cell` and trigger crashes. + + panic!(); + } + } + + let x = Cell::new(Foo { x: 22 }); + let _y = x.get(); + let _z = x.clone(); +} + +#[test] +fn refcell_default() { + let cell: RefCell = Default::default(); + assert_eq!(0, *cell.borrow()); +} + +#[test] +fn unsafe_cell_unsized() { + let cell: &UnsafeCell<[i32]> = &UnsafeCell::new([1, 2, 3]); + { + let val: &mut [i32] = unsafe { &mut *cell.get() }; + val[0] = 4; + val[2] = 5; + } + let comp: &mut [i32] = &mut [4, 2, 5]; + assert_eq!(unsafe { &mut *cell.get() }, comp); +} + +#[test] +fn refcell_unsized() { + let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); + { + let b = &mut *cell.borrow_mut(); + b[0] = 4; + b[2] = 5; + } + let comp: &mut [i32] = &mut [4, 2, 5]; + assert_eq!(&*cell.borrow(), comp); +} + +#[test] +fn refcell_ref_coercion() { + let cell: RefCell<[i32; 3]> = RefCell::new([1, 2, 3]); + { + let mut cellref: RefMut<'_, [i32; 3]> = cell.borrow_mut(); + cellref[0] = 4; + let mut coerced: RefMut<'_, [i32]> = cellref; + coerced[2] = 5; + } + { + let comp: &mut [i32] = &mut [4, 2, 5]; + let cellref: Ref<'_, [i32; 3]> = cell.borrow(); + assert_eq!(&*cellref, comp); + let coerced: Ref<'_, [i32]> = cellref; + assert_eq!(&*coerced, comp); + } +} + +#[test] +#[should_panic] +fn refcell_swap_borrows() { + let x = RefCell::new(0); + let _b = x.borrow(); + let y = RefCell::new(1); + x.swap(&y); +} + +#[test] +#[should_panic] +fn refcell_replace_borrows() { + let x = RefCell::new(0); + let _b = x.borrow(); + x.replace(1); +} + +#[test] +fn refcell_format() { + let name = RefCell::new("rust"); + let what = RefCell::new("rocks"); + let msg = format!("{name} {}", &*what.borrow(), name = &*name.borrow()); + assert_eq!(msg, "rust rocks".to_string()); +} + +#[allow(dead_code)] +fn const_cells() { + const UNSAFE_CELL: UnsafeCell = UnsafeCell::new(3); + const _: i32 = UNSAFE_CELL.into_inner(); + + const REF_CELL: RefCell = RefCell::new(3); + const _: i32 = REF_CELL.into_inner(); + + const CELL: Cell = Cell::new(3); + const _: i32 = CELL.into_inner(); + + /* FIXME(#110395) + const UNSAFE_CELL_FROM: UnsafeCell = UnsafeCell::from(3); + const _: i32 = UNSAFE_CELL.into_inner(); + + const REF_CELL_FROM: RefCell = RefCell::from(3); + const _: i32 = REF_CELL.into_inner(); + + const CELL_FROM: Cell = Cell::from(3); + const _: i32 = CELL.into_inner(); + */ +} diff --git a/library/coretests/tests/char.rs b/library/coretests/tests/char.rs new file mode 100644 index 00000000000..6422387e956 --- /dev/null +++ b/library/coretests/tests/char.rs @@ -0,0 +1,420 @@ +use std::str::FromStr; +use std::{char, str}; + +#[test] +fn test_convert() { + assert_eq!(u32::from('a'), 0x61); + assert_eq!(u64::from('b'), 0x62); + assert_eq!(u128::from('c'), 0x63); + assert_eq!(char::from(b'\0'), '\0'); + assert_eq!(char::from(b'a'), 'a'); + assert_eq!(char::from(b'\xFF'), '\u{FF}'); + assert_eq!(char::try_from(0_u32), Ok('\0')); + assert_eq!(char::try_from(0x61_u32), Ok('a')); + assert_eq!(char::try_from(0xD7FF_u32), Ok('\u{D7FF}')); + assert!(char::try_from(0xD800_u32).is_err()); + assert!(char::try_from(0xDFFF_u32).is_err()); + assert_eq!(char::try_from(0xE000_u32), Ok('\u{E000}')); + assert_eq!(char::try_from(0x10FFFF_u32), Ok('\u{10FFFF}')); + assert!(char::try_from(0x110000_u32).is_err()); + assert!(char::try_from(0xFFFF_FFFF_u32).is_err()); +} + +/* FIXME(#110395) +#[test] +const fn test_convert_const() { + assert!(u32::from('a') == 0x61); + assert!(u64::from('b') == 0x62); + assert!(u128::from('c') == 0x63); + assert!(char::from(b'\0') == '\0'); + assert!(char::from(b'a') == 'a'); + assert!(char::from(b'\xFF') == '\u{FF}'); +} +*/ + +#[test] +fn test_from_str() { + assert_eq!(char::from_str("a").unwrap(), 'a'); + assert_eq!(char::from_str("\0").unwrap(), '\0'); + assert_eq!(char::from_str("\u{D7FF}").unwrap(), '\u{d7FF}'); + assert!(char::from_str("").is_err()); + assert!(char::from_str("abc").is_err()); +} + +#[test] +fn test_is_lowercase() { + assert!('a'.is_lowercase()); + assert!('ö'.is_lowercase()); + assert!('ß'.is_lowercase()); + assert!(!'Ü'.is_lowercase()); + assert!(!'P'.is_lowercase()); +} + +#[test] +fn test_is_uppercase() { + assert!(!'h'.is_uppercase()); + assert!(!'ä'.is_uppercase()); + assert!(!'ß'.is_uppercase()); + assert!('Ö'.is_uppercase()); + assert!('T'.is_uppercase()); +} + +#[test] +fn test_is_whitespace() { + assert!(' '.is_whitespace()); + assert!('\u{2007}'.is_whitespace()); + assert!('\t'.is_whitespace()); + assert!('\n'.is_whitespace()); + assert!(!'a'.is_whitespace()); + assert!(!'_'.is_whitespace()); + assert!(!'\u{0}'.is_whitespace()); +} + +#[test] +fn test_to_digit() { + assert_eq!('0'.to_digit(10), Some(0)); + assert_eq!('1'.to_digit(2), Some(1)); + assert_eq!('2'.to_digit(3), Some(2)); + assert_eq!('9'.to_digit(10), Some(9)); + assert_eq!('a'.to_digit(16), Some(10)); + assert_eq!('A'.to_digit(16), Some(10)); + assert_eq!('b'.to_digit(16), Some(11)); + assert_eq!('B'.to_digit(16), Some(11)); + assert_eq!('A'.to_digit(36), Some(10)); + assert_eq!('z'.to_digit(36), Some(35)); + assert_eq!('Z'.to_digit(36), Some(35)); + assert_eq!('['.to_digit(36), None); + assert_eq!('`'.to_digit(36), None); + assert_eq!('{'.to_digit(36), None); + assert_eq!('$'.to_digit(36), None); + assert_eq!('@'.to_digit(16), None); + assert_eq!('G'.to_digit(16), None); + assert_eq!('g'.to_digit(16), None); + assert_eq!(' '.to_digit(10), None); + assert_eq!('/'.to_digit(10), None); + assert_eq!(':'.to_digit(10), None); + assert_eq!(':'.to_digit(11), None); +} + +#[test] +fn test_to_lowercase() { + fn lower(c: char) -> String { + let to_lowercase = c.to_lowercase(); + assert_eq!(to_lowercase.len(), to_lowercase.count()); + let iter: String = c.to_lowercase().collect(); + let disp: String = c.to_lowercase().to_string(); + assert_eq!(iter, disp); + let iter_rev: String = c.to_lowercase().rev().collect(); + let disp_rev: String = disp.chars().rev().collect(); + assert_eq!(iter_rev, disp_rev); + iter + } + assert_eq!(lower('A'), "a"); + assert_eq!(lower('Ö'), "ö"); + assert_eq!(lower('ß'), "ß"); + assert_eq!(lower('Ü'), "ü"); + assert_eq!(lower('💩'), "💩"); + assert_eq!(lower('Σ'), "σ"); + assert_eq!(lower('Τ'), "τ"); + assert_eq!(lower('Ι'), "ι"); + assert_eq!(lower('Γ'), "γ"); + assert_eq!(lower('Μ'), "μ"); + assert_eq!(lower('Α'), "α"); + assert_eq!(lower('Σ'), "σ"); + assert_eq!(lower('Dž'), "dž"); + assert_eq!(lower('fi'), "fi"); + assert_eq!(lower('İ'), "i\u{307}"); +} + +#[test] +fn test_to_uppercase() { + fn upper(c: char) -> String { + let to_uppercase = c.to_uppercase(); + assert_eq!(to_uppercase.len(), to_uppercase.count()); + let iter: String = c.to_uppercase().collect(); + let disp: String = c.to_uppercase().to_string(); + assert_eq!(iter, disp); + let iter_rev: String = c.to_uppercase().rev().collect(); + let disp_rev: String = disp.chars().rev().collect(); + assert_eq!(iter_rev, disp_rev); + iter + } + assert_eq!(upper('a'), "A"); + assert_eq!(upper('ö'), "Ö"); + assert_eq!(upper('ß'), "SS"); // not ẞ: Latin capital letter sharp s + assert_eq!(upper('ü'), "Ü"); + assert_eq!(upper('💩'), "💩"); + + assert_eq!(upper('σ'), "Σ"); + assert_eq!(upper('τ'), "Τ"); + assert_eq!(upper('ι'), "Ι"); + assert_eq!(upper('γ'), "Γ"); + assert_eq!(upper('μ'), "Μ"); + assert_eq!(upper('α'), "Α"); + assert_eq!(upper('ς'), "Σ"); + assert_eq!(upper('Dž'), "DŽ"); + assert_eq!(upper('fi'), "FI"); + assert_eq!(upper('ᾀ'), "ἈΙ"); +} + +#[test] +fn test_is_control() { + assert!('\u{0}'.is_control()); + assert!('\u{3}'.is_control()); + assert!('\u{6}'.is_control()); + assert!('\u{9}'.is_control()); + assert!('\u{7f}'.is_control()); + assert!('\u{92}'.is_control()); + assert!(!'\u{20}'.is_control()); + assert!(!'\u{55}'.is_control()); + assert!(!'\u{68}'.is_control()); +} + +#[test] +fn test_is_numeric() { + assert!('2'.is_numeric()); + assert!('7'.is_numeric()); + assert!('¾'.is_numeric()); + assert!(!'c'.is_numeric()); + assert!(!'i'.is_numeric()); + assert!(!'z'.is_numeric()); + assert!(!'Q'.is_numeric()); +} + +#[test] +fn test_escape_debug() { + fn string(c: char) -> String { + let iter: String = c.escape_debug().collect(); + let disp: String = c.escape_debug().to_string(); + assert_eq!(iter, disp); + iter + } + assert_eq!(string('\n'), "\\n"); + assert_eq!(string('\r'), "\\r"); + assert_eq!(string('\''), "\\'"); + assert_eq!(string('"'), "\\\""); + assert_eq!(string(' '), " "); + assert_eq!(string('a'), "a"); + assert_eq!(string('~'), "~"); + assert_eq!(string('é'), "é"); + assert_eq!(string('文'), "文"); + assert_eq!(string('\x00'), "\\0"); + assert_eq!(string('\x1f'), "\\u{1f}"); + assert_eq!(string('\x7f'), "\\u{7f}"); + assert_eq!(string('\u{80}'), "\\u{80}"); + assert_eq!(string('\u{ff}'), "\u{ff}"); + assert_eq!(string('\u{11b}'), "\u{11b}"); + assert_eq!(string('\u{1d4b6}'), "\u{1d4b6}"); + assert_eq!(string('\u{301}'), "\\u{301}"); // combining character + assert_eq!(string('\u{200b}'), "\\u{200b}"); // zero width space + assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1 + assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 +} + +#[test] +fn test_escape_default() { + fn string(c: char) -> String { + let iter: String = c.escape_default().collect(); + let disp: String = c.escape_default().to_string(); + assert_eq!(iter, disp); + iter + } + assert_eq!(string('\n'), "\\n"); + assert_eq!(string('\r'), "\\r"); + assert_eq!(string('\''), "\\'"); + assert_eq!(string('"'), "\\\""); + assert_eq!(string(' '), " "); + assert_eq!(string('a'), "a"); + assert_eq!(string('~'), "~"); + assert_eq!(string('é'), "\\u{e9}"); + assert_eq!(string('\x00'), "\\u{0}"); + assert_eq!(string('\x1f'), "\\u{1f}"); + assert_eq!(string('\x7f'), "\\u{7f}"); + assert_eq!(string('\u{80}'), "\\u{80}"); + assert_eq!(string('\u{ff}'), "\\u{ff}"); + assert_eq!(string('\u{11b}'), "\\u{11b}"); + assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}"); + assert_eq!(string('\u{200b}'), "\\u{200b}"); // zero width space + assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1 + assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 +} + +#[test] +fn test_escape_unicode() { + fn string(c: char) -> String { + let iter: String = c.escape_unicode().collect(); + let disp: String = c.escape_unicode().to_string(); + assert_eq!(iter, disp); + iter + } + + assert_eq!(string('\x00'), "\\u{0}"); + assert_eq!(string('\n'), "\\u{a}"); + assert_eq!(string(' '), "\\u{20}"); + assert_eq!(string('a'), "\\u{61}"); + assert_eq!(string('\u{11b}'), "\\u{11b}"); + assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}"); +} + +#[test] +fn test_encode_utf8() { + fn check(input: char, expect: &[u8]) { + let mut buf = [0; 4]; + let ptr = buf.as_ptr(); + let s = input.encode_utf8(&mut buf); + assert_eq!(s.as_ptr() as usize, ptr as usize); + assert!(str::from_utf8(s.as_bytes()).is_ok()); + assert_eq!(s.as_bytes(), expect); + } + + check('x', &[0x78]); + check('\u{e9}', &[0xc3, 0xa9]); + check('\u{a66e}', &[0xea, 0x99, 0xae]); + check('\u{1f4a9}', &[0xf0, 0x9f, 0x92, 0xa9]); +} + +#[test] +fn test_encode_utf16() { + fn check(input: char, expect: &[u16]) { + let mut buf = [0; 2]; + let ptr = buf.as_mut_ptr(); + let b = input.encode_utf16(&mut buf); + assert_eq!(b.as_mut_ptr() as usize, ptr as usize); + assert_eq!(b, expect); + } + + check('x', &[0x0078]); + check('\u{e9}', &[0x00e9]); + check('\u{a66e}', &[0xa66e]); + check('\u{1f4a9}', &[0xd83d, 0xdca9]); +} + +#[test] +fn test_len_utf16() { + assert!('x'.len_utf16() == 1); + assert!('\u{e9}'.len_utf16() == 1); + assert!('\u{a66e}'.len_utf16() == 1); + assert!('\u{1f4a9}'.len_utf16() == 2); +} + +#[test] +fn test_decode_utf16() { + fn check(s: &[u16], expected: &[Result]) { + let v = char::decode_utf16(s.iter().cloned()) + .map(|r| r.map_err(|e| e.unpaired_surrogate())) + .collect::>(); + assert_eq!(v, expected); + } + check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]); + check(&[0xD800, 0], &[Err(0xD800), Ok('\0')]); + check(&[0xD800], &[Err(0xD800)]); + check(&[0xD840, 0xDC00], &[Ok('\u{20000}')]); + check(&[0xD840, 0xD840, 0xDC00], &[Err(0xD840), Ok('\u{20000}')]); + check(&[0xDC00, 0xD840], &[Err(0xDC00), Err(0xD840)]); +} + +#[test] +fn test_decode_utf16_size_hint() { + fn check(s: &[u16]) { + let mut iter = char::decode_utf16(s.iter().cloned()); + + loop { + let count = iter.clone().count(); + let (lower, upper) = iter.size_hint(); + + assert!( + lower <= count && count <= upper.unwrap(), + "lower = {lower}, count = {count}, upper = {upper:?}" + ); + + if let None = iter.next() { + break; + } + } + } + + check(&[0xD800, 0xD800, 0xDC00]); + check(&[0xD800, 0xD800, 0x0]); + check(&[0xD800, 0x41, 0x42]); + check(&[0xD800, 0]); + check(&[0xD834, 0x006d]); +} + +#[test] +fn ed_iterator_specializations() { + // Check counting + assert_eq!('\n'.escape_default().count(), 2); + assert_eq!('c'.escape_default().count(), 1); + assert_eq!(' '.escape_default().count(), 1); + assert_eq!('\\'.escape_default().count(), 2); + assert_eq!('\''.escape_default().count(), 2); + + // Check nth + + // Check that OoB is handled correctly + assert_eq!('\n'.escape_default().nth(2), None); + assert_eq!('c'.escape_default().nth(1), None); + assert_eq!(' '.escape_default().nth(1), None); + assert_eq!('\\'.escape_default().nth(2), None); + assert_eq!('\''.escape_default().nth(2), None); + + // Check the first char + assert_eq!('\n'.escape_default().nth(0), Some('\\')); + assert_eq!('c'.escape_default().nth(0), Some('c')); + assert_eq!(' '.escape_default().nth(0), Some(' ')); + assert_eq!('\\'.escape_default().nth(0), Some('\\')); + assert_eq!('\''.escape_default().nth(0), Some('\\')); + + // Check the second char + assert_eq!('\n'.escape_default().nth(1), Some('n')); + assert_eq!('\\'.escape_default().nth(1), Some('\\')); + assert_eq!('\''.escape_default().nth(1), Some('\'')); + + // Check the last char + assert_eq!('\n'.escape_default().last(), Some('n')); + assert_eq!('c'.escape_default().last(), Some('c')); + assert_eq!(' '.escape_default().last(), Some(' ')); + assert_eq!('\\'.escape_default().last(), Some('\\')); + assert_eq!('\''.escape_default().last(), Some('\'')); +} + +#[test] +fn eu_iterator_specializations() { + fn check(c: char) { + let len = c.escape_unicode().count(); + + // Check OoB + assert_eq!(c.escape_unicode().nth(len), None); + + // For all possible in-bound offsets + let mut iter = c.escape_unicode(); + for offset in 0..len { + // Check last + assert_eq!(iter.clone().last(), Some('}')); + + // Check len + assert_eq!(iter.len(), len - offset); + + // Check size_hint (= len in ExactSizeIterator) + assert_eq!(iter.size_hint(), (iter.len(), Some(iter.len()))); + + // Check counting + assert_eq!(iter.clone().count(), len - offset); + + // Check nth + assert_eq!(c.escape_unicode().nth(offset), iter.next()); + } + + // Check post-last + assert_eq!(iter.clone().last(), None); + assert_eq!(iter.clone().count(), 0); + } + + check('\u{0}'); + check('\u{1}'); + check('\u{12}'); + check('\u{123}'); + check('\u{1234}'); + check('\u{12340}'); + check('\u{10FFFF}'); +} diff --git a/library/coretests/tests/clone.rs b/library/coretests/tests/clone.rs new file mode 100644 index 00000000000..054b1d3d498 --- /dev/null +++ b/library/coretests/tests/clone.rs @@ -0,0 +1,123 @@ +use core::clone::CloneToUninit; +use core::ffi::CStr; +use core::mem::MaybeUninit; +use core::ptr; + +#[test] +#[allow(suspicious_double_ref_op)] +fn test_borrowed_clone() { + let x = 5; + let y: &i32 = &x; + let z: &i32 = (&y).clone(); + assert_eq!(*z, 5); +} + +#[test] +fn test_clone_from() { + let a = Box::new(5); + let mut b = Box::new(10); + b.clone_from(&a); + assert_eq!(*b, 5); +} + +#[test] +fn test_clone_to_uninit_slice_success() { + // Using `String`s to exercise allocation and Drop of the individual elements; + // if something is aliased or double-freed, at least Miri will catch that. + let a: [String; 3] = ["a", "b", "c"].map(String::from); + + let mut storage: MaybeUninit<[String; 3]> = MaybeUninit::uninit(); + let b: [String; 3] = unsafe { + a[..].clone_to_uninit(storage.as_mut_ptr().cast()); + storage.assume_init() + }; + + assert_eq!(a, b); +} + +#[test] +#[cfg(panic = "unwind")] +fn test_clone_to_uninit_slice_drops_on_panic() { + use core::sync::atomic::AtomicUsize; + use core::sync::atomic::Ordering::Relaxed; + + /// A static counter is OK to use as long as _this one test_ isn't run several times in + /// multiple threads. + static COUNTER: AtomicUsize = AtomicUsize::new(0); + /// Counts how many instances are live, and panics if a fifth one is created + struct CountsDropsAndPanics {} + impl CountsDropsAndPanics { + fn new() -> Self { + COUNTER.fetch_add(1, Relaxed); + Self {} + } + } + impl Clone for CountsDropsAndPanics { + fn clone(&self) -> Self { + if COUNTER.load(Relaxed) == 4 { panic!("intentional panic") } else { Self::new() } + } + } + impl Drop for CountsDropsAndPanics { + fn drop(&mut self) { + COUNTER.fetch_sub(1, Relaxed); + } + } + + let a: [CountsDropsAndPanics; 3] = core::array::from_fn(|_| CountsDropsAndPanics::new()); + assert_eq!(COUNTER.load(Relaxed), 3); + + let panic_payload = std::panic::catch_unwind(|| { + let mut storage: MaybeUninit<[CountsDropsAndPanics; 3]> = MaybeUninit::uninit(); + // This should panic halfway through + unsafe { + a[..].clone_to_uninit(storage.as_mut_ptr().cast()); + } + }) + .unwrap_err(); + assert_eq!(panic_payload.downcast().unwrap(), Box::new("intentional panic")); + + // Check for lack of leak, which is what this test is looking for + assert_eq!(COUNTER.load(Relaxed), 3, "leaked during clone!"); + + // Might as well exercise the rest of the drops + drop(a); + assert_eq!(COUNTER.load(Relaxed), 0); +} + +#[test] +fn test_clone_to_uninit_str() { + let a = "hello"; + + let mut storage: MaybeUninit<[u8; 5]> = MaybeUninit::uninit(); + unsafe { a.clone_to_uninit(storage.as_mut_ptr().cast()) }; + assert_eq!(a.as_bytes(), unsafe { storage.assume_init() }.as_slice()); + + let mut b: Box = "world".into(); + assert_eq!(a.len(), b.len()); + assert_ne!(a, &*b); + unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; + assert_eq!(a, &*b); +} + +#[test] +fn test_clone_to_uninit_cstr() { + let a = c"hello"; + + let mut storage: MaybeUninit<[u8; 6]> = MaybeUninit::uninit(); + unsafe { a.clone_to_uninit(storage.as_mut_ptr().cast()) }; + assert_eq!(a.to_bytes_with_nul(), unsafe { storage.assume_init() }.as_slice()); + + let mut b: Box = c"world".into(); + assert_eq!(a.count_bytes(), b.count_bytes()); + assert_ne!(a, &*b); + unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; + assert_eq!(a, &*b); +} + +#[test] +fn cstr_metadata_is_length_with_nul() { + let s: &CStr = c"abcdef"; + let p: *const CStr = ptr::from_ref(s); + let bytes: *const [u8] = p as *const [u8]; + assert_eq!(s.to_bytes_with_nul().len(), bytes.len()); +} diff --git a/library/coretests/tests/cmp.rs b/library/coretests/tests/cmp.rs new file mode 100644 index 00000000000..6c4e2146f91 --- /dev/null +++ b/library/coretests/tests/cmp.rs @@ -0,0 +1,250 @@ +use core::cmp::Ordering::{self, *}; +use core::cmp::{self}; + +#[test] +fn test_int_totalord() { + assert_eq!(5.cmp(&10), Less); + assert_eq!(10.cmp(&5), Greater); + assert_eq!(5.cmp(&5), Equal); + assert_eq!((-5).cmp(&12), Less); + assert_eq!(12.cmp(&-5), Greater); +} + +#[test] +fn test_bool_totalord() { + assert_eq!(true.cmp(&false), Greater); + assert_eq!(false.cmp(&true), Less); + assert_eq!(true.cmp(&true), Equal); + assert_eq!(false.cmp(&false), Equal); +} + +#[test] +fn test_mut_int_totalord() { + assert_eq!((&mut 5).cmp(&&mut 10), Less); + assert_eq!((&mut 10).cmp(&&mut 5), Greater); + assert_eq!((&mut 5).cmp(&&mut 5), Equal); + assert_eq!((&mut -5).cmp(&&mut 12), Less); + assert_eq!((&mut 12).cmp(&&mut -5), Greater); +} + +#[test] +fn test_ord_max_min() { + assert_eq!(1.max(2), 2); + assert_eq!(2.max(1), 2); + assert_eq!(1.min(2), 1); + assert_eq!(2.min(1), 1); + assert_eq!(1.max(1), 1); + assert_eq!(1.min(1), 1); +} + +#[test] +fn test_ord_min_max_by() { + let f = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); + assert_eq!(cmp::min_by(1, -1, f), 1); + assert_eq!(cmp::min_by(1, -2, f), 1); + assert_eq!(cmp::min_by(2, -1, f), -1); + assert_eq!(cmp::max_by(1, -1, f), -1); + assert_eq!(cmp::max_by(1, -2, f), -2); + assert_eq!(cmp::max_by(2, -1, f), 2); +} + +#[test] +fn test_ord_min_max_by_key() { + let f = |x: &i32| x.abs(); + assert_eq!(cmp::min_by_key(1, -1, f), 1); + assert_eq!(cmp::min_by_key(1, -2, f), 1); + assert_eq!(cmp::min_by_key(2, -1, f), -1); + assert_eq!(cmp::max_by_key(1, -1, f), -1); + assert_eq!(cmp::max_by_key(1, -2, f), -2); + assert_eq!(cmp::max_by_key(2, -1, f), 2); +} + +#[test] +fn test_ordering_reverse() { + assert_eq!(Less.reverse(), Greater); + assert_eq!(Equal.reverse(), Equal); + assert_eq!(Greater.reverse(), Less); +} + +#[test] +fn test_ordering_order() { + assert!(Less < Equal); + assert_eq!(Greater.cmp(&Less), Greater); +} + +#[test] +fn test_ordering_then() { + assert_eq!(Equal.then(Less), Less); + assert_eq!(Equal.then(Equal), Equal); + assert_eq!(Equal.then(Greater), Greater); + assert_eq!(Less.then(Less), Less); + assert_eq!(Less.then(Equal), Less); + assert_eq!(Less.then(Greater), Less); + assert_eq!(Greater.then(Less), Greater); + assert_eq!(Greater.then(Equal), Greater); + assert_eq!(Greater.then(Greater), Greater); +} + +#[test] +fn test_ordering_then_with() { + assert_eq!(Equal.then_with(|| Less), Less); + assert_eq!(Equal.then_with(|| Equal), Equal); + assert_eq!(Equal.then_with(|| Greater), Greater); + assert_eq!(Less.then_with(|| Less), Less); + assert_eq!(Less.then_with(|| Equal), Less); + assert_eq!(Less.then_with(|| Greater), Less); + assert_eq!(Greater.then_with(|| Less), Greater); + assert_eq!(Greater.then_with(|| Equal), Greater); + assert_eq!(Greater.then_with(|| Greater), Greater); +} + +#[test] +fn test_user_defined_eq() { + // Our type. + struct SketchyNum { + num: isize, + } + + // Our implementation of `PartialEq` to support `==` and `!=`. + impl PartialEq for SketchyNum { + // Our custom eq allows numbers which are near each other to be equal! :D + fn eq(&self, other: &SketchyNum) -> bool { + (self.num - other.num).abs() < 5 + } + } + + // Now these binary operators will work when applied! + assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 }); + assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 }); +} + +#[test] +fn ordering_const() { + // test that the methods of `Ordering` are usable in a const context + + const ORDERING: Ordering = Greater; + + const REVERSE: Ordering = ORDERING.reverse(); + assert_eq!(REVERSE, Less); + + const THEN: Ordering = Equal.then(ORDERING); + assert_eq!(THEN, Greater); +} + +#[test] +fn ordering_structural_eq() { + // test that consts of type `Ordering` are usable in patterns + + const ORDERING: Ordering = Greater; + + const REVERSE: Ordering = ORDERING.reverse(); + match Ordering::Less { + REVERSE => {} + _ => unreachable!(), + }; +} + +#[test] +fn cmp_default() { + // Test default methods in PartialOrd and PartialEq + + #[derive(Debug)] + struct Fool(bool); + + impl PartialEq for Fool { + fn eq(&self, other: &Fool) -> bool { + let Fool(this) = *self; + let Fool(other) = *other; + this != other + } + } + + struct Int(isize); + + impl PartialEq for Int { + fn eq(&self, other: &Int) -> bool { + let Int(this) = *self; + let Int(other) = *other; + this == other + } + } + + impl PartialOrd for Int { + fn partial_cmp(&self, other: &Int) -> Option { + let Int(this) = *self; + let Int(other) = *other; + this.partial_cmp(&other) + } + } + + struct RevInt(isize); + + impl PartialEq for RevInt { + fn eq(&self, other: &RevInt) -> bool { + let RevInt(this) = *self; + let RevInt(other) = *other; + this == other + } + } + + impl PartialOrd for RevInt { + fn partial_cmp(&self, other: &RevInt) -> Option { + let RevInt(this) = *self; + let RevInt(other) = *other; + other.partial_cmp(&this) + } + } + + assert!(Int(2) > Int(1)); + assert!(Int(2) >= Int(1)); + assert!(Int(1) >= Int(1)); + assert!(Int(1) < Int(2)); + assert!(Int(1) <= Int(2)); + assert!(Int(1) <= Int(1)); + + assert!(RevInt(2) < RevInt(1)); + assert!(RevInt(2) <= RevInt(1)); + assert!(RevInt(1) <= RevInt(1)); + assert!(RevInt(1) > RevInt(2)); + assert!(RevInt(1) >= RevInt(2)); + assert!(RevInt(1) >= RevInt(1)); + + assert_eq!(Fool(true), Fool(false)); + assert!(Fool(true) != Fool(true)); + assert!(Fool(false) != Fool(false)); + assert_eq!(Fool(false), Fool(true)); +} + +/* FIXME(#110395) +mod const_cmp { + use super::*; + + struct S(i32); + + impl PartialEq for S { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl PartialOrd for S { + fn partial_cmp(&self, other: &Self) -> Option { + let ret = match (self.0, other.0) { + (a, b) if a > b => Ordering::Greater, + (a, b) if a < b => Ordering::Less, + _ => Ordering::Equal, + }; + + Some(ret) + } + } + + const _: () = assert!(S(1) == S(1)); + const _: () = assert!(S(0) != S(1)); + + const _: () = assert!(S(1) <= S(1)); + const _: () = assert!(S(1) >= S(1)); + const _: () = assert!(S(0) < S(1)); + const _: () = assert!(S(1) > S(0)); +} +*/ diff --git a/library/coretests/tests/const_ptr.rs b/library/coretests/tests/const_ptr.rs new file mode 100644 index 00000000000..d874f08317f --- /dev/null +++ b/library/coretests/tests/const_ptr.rs @@ -0,0 +1,101 @@ +// Aligned to two bytes +const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x45, 0x67])]; + +const fn unaligned_ptr() -> *const u16 { + // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16 + unsafe { DATA.as_ptr().byte_add(1) } +} + +#[test] +fn read() { + use core::ptr; + + const FOO: i32 = unsafe { ptr::read(&42 as *const i32) }; + assert_eq!(FOO, 42); + + const ALIGNED: i32 = unsafe { ptr::read_unaligned(&42 as *const i32) }; + assert_eq!(ALIGNED, 42); + + const UNALIGNED_PTR: *const u16 = unaligned_ptr(); + + const UNALIGNED: u16 = unsafe { ptr::read_unaligned(UNALIGNED_PTR) }; + assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); +} + +#[test] +fn const_ptr_read() { + const FOO: i32 = unsafe { (&42 as *const i32).read() }; + assert_eq!(FOO, 42); + + const ALIGNED: i32 = unsafe { (&42 as *const i32).read_unaligned() }; + assert_eq!(ALIGNED, 42); + + const UNALIGNED_PTR: *const u16 = unaligned_ptr(); + + const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; + assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); +} + +#[test] +fn mut_ptr_read() { + const FOO: i32 = unsafe { (&42 as *const i32 as *mut i32).read() }; + assert_eq!(FOO, 42); + + const ALIGNED: i32 = unsafe { (&42 as *const i32 as *mut i32).read_unaligned() }; + assert_eq!(ALIGNED, 42); + + const UNALIGNED_PTR: *mut u16 = unaligned_ptr() as *mut u16; + + const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; + assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); +} + +#[test] +fn write() { + use core::ptr; + + const fn write_aligned() -> i32 { + let mut res = 0; + unsafe { + ptr::write(&mut res as *mut _, 42); + } + res + } + const ALIGNED: i32 = write_aligned(); + assert_eq!(ALIGNED, 42); + + const fn write_unaligned() -> [u16; 2] { + let mut two_aligned = [0u16; 2]; + unsafe { + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); + ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); + } + two_aligned + } + const UNALIGNED: [u16; 2] = write_unaligned(); + assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); +} + +#[test] +fn mut_ptr_write() { + const fn aligned() -> i32 { + let mut res = 0; + unsafe { + (&mut res as *mut i32).write(42); + } + res + } + const ALIGNED: i32 = aligned(); + assert_eq!(ALIGNED, 42); + + const fn write_unaligned() -> [u16; 2] { + let mut two_aligned = [0u16; 2]; + unsafe { + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); + unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); + } + two_aligned + } + const UNALIGNED: [u16; 2] = write_unaligned(); + assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); +} diff --git a/library/coretests/tests/convert.rs b/library/coretests/tests/convert.rs new file mode 100644 index 00000000000..f76dd277884 --- /dev/null +++ b/library/coretests/tests/convert.rs @@ -0,0 +1,18 @@ +/* FIXME(#110395) +#[test] +fn convert() { + const fn from(x: i32) -> i32 { + i32::from(x) + } + + const FOO: i32 = from(42); + assert_eq!(FOO, 42); + + const fn into(x: Vec) -> Vec { + x.into() + } + + const BAR: Vec = into(Vec::new()); + assert_eq!(BAR, Vec::::new()); +} +*/ diff --git a/library/coretests/tests/error.rs b/library/coretests/tests/error.rs new file mode 100644 index 00000000000..996566d3848 --- /dev/null +++ b/library/coretests/tests/error.rs @@ -0,0 +1,66 @@ +use core::error::{Request, request_ref, request_value}; + +// Test the `Request` API. +#[derive(Debug)] +struct SomeConcreteType { + some_string: String, +} + +impl std::fmt::Display for SomeConcreteType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "A") + } +} + +impl std::error::Error for SomeConcreteType { + fn provide<'a>(&'a self, request: &mut Request<'a>) { + request + .provide_ref::(&self.some_string) + .provide_ref::(&self.some_string) + .provide_value_with::(|| "bye".to_owned()); + } +} + +// Test the Error.provide and request mechanisms with a by-reference trait object. +#[test] +fn test_error_generic_member_access() { + let obj = &SomeConcreteType { some_string: "hello".to_owned() }; + + assert_eq!(request_ref::(&*obj).unwrap(), "hello"); + assert_eq!(request_value::(&*obj).unwrap(), "bye"); + assert_eq!(request_value::(&obj), None); +} + +// Test the Error.provide and request mechanisms with a by-reference trait object. +#[test] +fn test_request_constructor() { + let obj: &dyn std::error::Error = &SomeConcreteType { some_string: "hello".to_owned() }; + + assert_eq!(request_ref::(&*obj).unwrap(), "hello"); + assert_eq!(request_value::(&*obj).unwrap(), "bye"); + assert_eq!(request_value::(&obj), None); +} + +// Test the Error.provide and request mechanisms with a boxed trait object. +#[test] +fn test_error_generic_member_access_boxed() { + let obj: Box = + Box::new(SomeConcreteType { some_string: "hello".to_owned() }); + + assert_eq!(request_ref::(&*obj).unwrap(), "hello"); + assert_eq!(request_value::(&*obj).unwrap(), "bye"); + + // NOTE: Box only implements Error when E: Error + Sized, which means we can't pass a + // Box to request_value. + //assert_eq!(request_value::(&obj).unwrap(), "bye"); +} + +// Test the Error.provide and request mechanisms with a concrete object. +#[test] +fn test_error_generic_member_access_concrete() { + let obj = SomeConcreteType { some_string: "hello".to_owned() }; + + assert_eq!(request_ref::(&obj).unwrap(), "hello"); + assert_eq!(request_value::(&obj).unwrap(), "bye"); + assert_eq!(request_value::(&obj), None); +} diff --git a/library/coretests/tests/ffi.rs b/library/coretests/tests/ffi.rs new file mode 100644 index 00000000000..2b33fbd95f0 --- /dev/null +++ b/library/coretests/tests/ffi.rs @@ -0,0 +1 @@ +mod cstr; diff --git a/library/coretests/tests/ffi/cstr.rs b/library/coretests/tests/ffi/cstr.rs new file mode 100644 index 00000000000..9bf4c21a9ab --- /dev/null +++ b/library/coretests/tests/ffi/cstr.rs @@ -0,0 +1,15 @@ +use core::ffi::CStr; + +#[test] +fn compares_as_u8s() { + let a: &CStr = c"Hello!"; // Starts with ascii + let a_bytes: &[u8] = a.to_bytes(); + assert!((..0b1000_0000).contains(&a_bytes[0])); + + let b: &CStr = c"こんにちは!"; // Starts with non ascii + let b_bytes: &[u8] = b.to_bytes(); + assert!((0b1000_0000..).contains(&b_bytes[0])); + + assert_eq!(Ord::cmp(a, b), Ord::cmp(a_bytes, b_bytes)); + assert_eq!(PartialOrd::partial_cmp(a, b), PartialOrd::partial_cmp(a_bytes, b_bytes)); +} diff --git a/library/coretests/tests/fmt/builders.rs b/library/coretests/tests/fmt/builders.rs new file mode 100644 index 00000000000..ba4801f5912 --- /dev/null +++ b/library/coretests/tests/fmt/builders.rs @@ -0,0 +1,1044 @@ +mod debug_struct { + use std::fmt; + + #[test] + fn test_empty() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo").finish() + } + } + + assert_eq!("Foo", format!("{Foo:?}")); + assert_eq!("Foo", format!("{Foo:#?}")); + } + + #[test] + fn test_single() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo").field("bar", &true).finish() + } + } + + assert_eq!("Foo { bar: true }", format!("{Foo:?}")); + assert_eq!( + "Foo { + bar: true, +}", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_multiple() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo") + .field("bar", &true) + .field("baz", &format_args!("{}/{}", 10, 20)) + .finish() + } + } + + assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{Foo:?}")); + assert_eq!( + "Foo { + bar: true, + baz: 10/20, +}", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo") + .field("bar", &true) + .field("baz", &format_args!("{}/{}", 10, 20)) + .finish() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Bar").field("foo", &Foo).field("hello", &"world").finish() + } + } + + assert_eq!( + r#"Bar { foo: Foo { bar: true, baz: 10/20 }, hello: "world" }"#, + format!("{Bar:?}") + ); + assert_eq!( + r#"Bar { + foo: Foo { + bar: true, + baz: 10/20, + }, + hello: "world", +}"#, + format!("{Bar:#?}") + ); + } + + #[test] + fn test_empty_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo").finish_non_exhaustive() + } + } + + assert_eq!("Foo { .. }", format!("{Foo:?}")); + assert_eq!("Foo { .. }", format!("{Foo:#?}")); + } + + #[test] + fn test_multiple_and_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo") + .field("bar", &true) + .field("baz", &format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{Foo:?}")); + assert_eq!( + "Foo { + bar: true, + baz: 10/20, + .. +}", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo") + .field("bar", &true) + .field("baz", &format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Bar") + .field("foo", &Foo) + .field("hello", &"world") + .finish_non_exhaustive() + } + } + + assert_eq!( + r#"Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: "world", .. }"#, + format!("{Bar:?}") + ); + assert_eq!( + r#"Bar { + foo: Foo { + bar: true, + baz: 10/20, + .. + }, + hello: "world", + .. +}"#, + format!("{Bar:#?}") + ); + } +} + +mod debug_tuple { + use std::fmt; + + #[test] + fn test_empty() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo").finish() + } + } + + assert_eq!("Foo", format!("{Foo:?}")); + assert_eq!("Foo", format!("{Foo:#?}")); + } + + #[test] + fn test_single() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo").field(&true).finish() + } + } + + assert_eq!("Foo(true)", format!("{Foo:?}")); + assert_eq!( + "Foo( + true, +)", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_multiple() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo").field(&true).field(&format_args!("{}/{}", 10, 20)).finish() + } + } + + assert_eq!("Foo(true, 10/20)", format!("{Foo:?}")); + assert_eq!( + "Foo( + true, + 10/20, +)", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo").field(&true).field(&format_args!("{}/{}", 10, 20)).finish() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Bar").field(&Foo).field(&"world").finish() + } + } + + assert_eq!(r#"Bar(Foo(true, 10/20), "world")"#, format!("{Bar:?}")); + assert_eq!( + r#"Bar( + Foo( + true, + 10/20, + ), + "world", +)"#, + format!("{Bar:#?}") + ); + } + + #[test] + fn test_empty_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo").finish_non_exhaustive() + } + } + + assert_eq!("Foo(..)", format!("{Foo:?}")); + assert_eq!("Foo(..)", format!("{Foo:#?}")); + } + + #[test] + fn test_multiple_and_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo") + .field(&true) + .field(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!("Foo(true, 10/20, ..)", format!("{Foo:?}")); + assert_eq!( + "Foo( + true, + 10/20, + .. +)", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo") + .field(&true) + .field(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Bar").field(&Foo).field(&"world").finish_non_exhaustive() + } + } + + assert_eq!(r#"Bar(Foo(true, 10/20, ..), "world", ..)"#, format!("{Bar:?}")); + assert_eq!( + r#"Bar( + Foo( + true, + 10/20, + .. + ), + "world", + .. +)"#, + format!("{Bar:#?}") + ); + } +} + +mod debug_map { + use std::fmt; + + #[test] + fn test_empty() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().finish() + } + } + + assert_eq!("{}", format!("{Foo:?}")); + assert_eq!("{}", format!("{Foo:#?}")); + } + + #[test] + fn test_single() { + struct Entry; + + impl fmt::Debug for Entry { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().entry(&"bar", &true).finish() + } + } + + struct KeyValue; + + impl fmt::Debug for KeyValue { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().key(&"bar").value(&true).finish() + } + } + + assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}")); + assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}")); + + assert_eq!(r#"{"bar": true}"#, format!("{Entry:?}")); + assert_eq!( + r#"{ + "bar": true, +}"#, + format!("{Entry:#?}") + ); + } + + #[test] + fn test_multiple() { + struct Entry; + + impl fmt::Debug for Entry { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map() + .entry(&"bar", &true) + .entry(&10, &format_args!("{}/{}", 10, 20)) + .finish() + } + } + + struct KeyValue; + + impl fmt::Debug for KeyValue { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map() + .key(&"bar") + .value(&true) + .key(&10) + .value(&format_args!("{}/{}", 10, 20)) + .finish() + } + } + + assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}")); + assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}")); + + assert_eq!(r#"{"bar": true, 10: 10/20}"#, format!("{Entry:?}")); + assert_eq!( + r#"{ + "bar": true, + 10: 10/20, +}"#, + format!("{Entry:#?}") + ); + } + + #[test] + fn test_nested() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map() + .entry(&"bar", &true) + .entry(&10, &format_args!("{}/{}", 10, 20)) + .finish() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().entry(&"foo", &Foo).entry(&Foo, &"world").finish() + } + } + + assert_eq!( + r#"{"foo": {"bar": true, 10: 10/20}, {"bar": true, 10: 10/20}: "world"}"#, + format!("{Bar:?}") + ); + assert_eq!( + r#"{ + "foo": { + "bar": true, + 10: 10/20, + }, + { + "bar": true, + 10: 10/20, + }: "world", +}"#, + format!("{Bar:#?}") + ); + } + + #[test] + fn test_entry_err() { + // Ensure errors in a map entry don't trigger panics (#65231) + use std::fmt::Write; + + struct ErrorFmt; + + impl fmt::Debug for ErrorFmt { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + Err(fmt::Error) + } + } + + struct KeyValue(usize, K, V); + + impl fmt::Debug for KeyValue + where + K: fmt::Debug, + V: fmt::Debug, + { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut map = fmt.debug_map(); + + for _ in 0..self.0 { + map.entry(&self.1, &self.2); + } + + map.finish() + } + } + + let mut buf = String::new(); + + assert!(write!(&mut buf, "{:?}", KeyValue(1, ErrorFmt, "bar")).is_err()); + assert!(write!(&mut buf, "{:?}", KeyValue(1, "foo", ErrorFmt)).is_err()); + + assert!(write!(&mut buf, "{:?}", KeyValue(2, ErrorFmt, "bar")).is_err()); + assert!(write!(&mut buf, "{:?}", KeyValue(2, "foo", ErrorFmt)).is_err()); + } + + #[test] + #[should_panic] + fn test_invalid_key_when_entry_is_incomplete() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().key(&"bar").key(&"invalid").finish() + } + } + + let _ = format!("{Foo:?}"); + } + + #[test] + #[should_panic] + fn test_invalid_finish_incomplete_entry() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().key(&"bar").finish() + } + } + + let _ = format!("{Foo:?}"); + } + + #[test] + #[should_panic] + fn test_invalid_value_before_key() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().value(&"invalid").key(&"bar").finish() + } + } + + let _ = format!("{Foo:?}"); + } + + #[test] + fn test_empty_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().finish_non_exhaustive() + } + } + + assert_eq!("{..}", format!("{Foo:?}")); + assert_eq!("{..}", format!("{Foo:#?}")); + } + + #[test] + fn test_multiple_and_non_exhaustive() { + struct Entry; + + impl fmt::Debug for Entry { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map() + .entry(&"bar", &true) + .entry(&10, &format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct KeyValue; + + impl fmt::Debug for KeyValue { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map() + .key(&"bar") + .value(&true) + .key(&10) + .value(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}")); + assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}")); + + assert_eq!(r#"{"bar": true, 10: 10/20, ..}"#, format!("{Entry:?}")); + assert_eq!( + r#"{ + "bar": true, + 10: 10/20, + .. +}"#, + format!("{Entry:#?}") + ); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map() + .entry(&"bar", &true) + .entry(&10, &format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().entry(&"foo", &Foo).entry(&Foo, &"world").finish_non_exhaustive() + } + } + + assert_eq!( + r#"{"foo": {"bar": true, 10: 10/20, ..}, {"bar": true, 10: 10/20, ..}: "world", ..}"#, + format!("{Bar:?}") + ); + assert_eq!( + r#"{ + "foo": { + "bar": true, + 10: 10/20, + .. + }, + { + "bar": true, + 10: 10/20, + .. + }: "world", + .. +}"#, + format!("{Bar:#?}") + ); + } +} + +mod debug_set { + use std::fmt; + + #[test] + fn test_empty() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set().finish() + } + } + + assert_eq!("{}", format!("{Foo:?}")); + assert_eq!("{}", format!("{Foo:#?}")); + } + + #[test] + fn test_single() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set().entry(&true).finish() + } + } + + assert_eq!("{true}", format!("{Foo:?}")); + assert_eq!( + "{ + true, +}", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_multiple() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish() + } + } + + assert_eq!("{true, 10/20}", format!("{Foo:?}")); + assert_eq!( + "{ + true, + 10/20, +}", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set().entry(&Foo).entry(&"world").finish() + } + } + + assert_eq!(r#"{{true, 10/20}, "world"}"#, format!("{Bar:?}")); + assert_eq!( + r#"{ + { + true, + 10/20, + }, + "world", +}"#, + format!("{Bar:#?}") + ); + } + + #[test] + fn test_empty_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set().finish_non_exhaustive() + } + } + + assert_eq!("{..}", format!("{Foo:?}")); + assert_eq!("{..}", format!("{Foo:#?}")); + } + + #[test] + fn test_multiple_and_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set() + .entry(&true) + .entry(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!("{true, 10/20, ..}", format!("{Foo:?}")); + assert_eq!( + "{ + true, + 10/20, + .. +}", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set() + .entry(&true) + .entry(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set().entry(&Foo).entry(&"world").finish_non_exhaustive() + } + } + + assert_eq!(r#"{{true, 10/20, ..}, "world", ..}"#, format!("{Bar:?}")); + assert_eq!( + r#"{ + { + true, + 10/20, + .. + }, + "world", + .. +}"#, + format!("{Bar:#?}") + ); + } +} + +mod debug_list { + use std::fmt; + + #[test] + fn test_empty() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().finish() + } + } + + assert_eq!("[]", format!("{Foo:?}")); + assert_eq!("[]", format!("{Foo:#?}")); + } + + #[test] + fn test_single() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().entry(&true).finish() + } + } + + assert_eq!("[true]", format!("{Foo:?}")); + assert_eq!( + "[ + true, +]", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_multiple() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish() + } + } + + assert_eq!("[true, 10/20]", format!("{Foo:?}")); + assert_eq!( + "[ + true, + 10/20, +]", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().entry(&Foo).entry(&"world").finish() + } + } + + assert_eq!(r#"[[true, 10/20], "world"]"#, format!("{Bar:?}")); + assert_eq!( + r#"[ + [ + true, + 10/20, + ], + "world", +]"#, + format!("{Bar:#?}") + ); + } + + #[test] + fn test_empty_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().finish_non_exhaustive() + } + } + + assert_eq!("[..]", format!("{Foo:?}")); + assert_eq!("[..]", format!("{Foo:#?}")); + } + + #[test] + fn test_multiple_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list() + .entry(&true) + .entry(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!("[true, 10/20, ..]", format!("{Foo:?}")); + assert_eq!( + "[ + true, + 10/20, + .. +]", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list() + .entry(&true) + .entry(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().entry(&Foo).entry(&"world").finish_non_exhaustive() + } + } + + assert_eq!(r#"[[true, 10/20, ..], "world", ..]"#, format!("{Bar:?}")); + assert_eq!( + r#"[ + [ + true, + 10/20, + .. + ], + "world", + .. +]"#, + format!("{Bar:#?}") + ); + } +} + +#[test] +fn test_formatting_parameters_are_forwarded() { + use std::collections::{BTreeMap, BTreeSet}; + #[derive(Debug)] + #[allow(dead_code)] + struct Foo { + bar: u32, + baz: u32, + } + let struct_ = Foo { bar: 1024, baz: 7 }; + let tuple = (1024, 7); + let list = [1024, 7]; + let mut map = BTreeMap::new(); + map.insert("bar", 1024); + map.insert("baz", 7); + let mut set = BTreeSet::new(); + set.insert(1024); + set.insert(7); + + assert_eq!(format!("{struct_:03?}"), "Foo { bar: 1024, baz: 007 }"); + assert_eq!(format!("{tuple:03?}"), "(1024, 007)"); + assert_eq!(format!("{list:03?}"), "[1024, 007]"); + assert_eq!(format!("{map:03?}"), r#"{"bar": 1024, "baz": 007}"#); + assert_eq!(format!("{set:03?}"), "{007, 1024}"); + assert_eq!( + format!("{struct_:#03?}"), + " +Foo { + bar: 1024, + baz: 007, +} + " + .trim() + ); + assert_eq!( + format!("{tuple:#03?}"), + " +( + 1024, + 007, +) + " + .trim() + ); + assert_eq!( + format!("{list:#03?}"), + " +[ + 1024, + 007, +] + " + .trim() + ); + assert_eq!( + format!("{map:#03?}"), + r#" +{ + "bar": 1024, + "baz": 007, +} + "# + .trim() + ); + assert_eq!( + format!("{set:#03?}"), + " +{ + 007, + 1024, +} + " + .trim() + ); +} diff --git a/library/coretests/tests/fmt/float.rs b/library/coretests/tests/fmt/float.rs new file mode 100644 index 00000000000..003782f34dc --- /dev/null +++ b/library/coretests/tests/fmt/float.rs @@ -0,0 +1,175 @@ +#[test] +fn test_format_f64() { + assert_eq!("1", format!("{:.0}", 1.0f64)); + assert_eq!("9", format!("{:.0}", 9.4f64)); + assert_eq!("10", format!("{:.0}", 9.9f64)); + assert_eq!("9.8", format!("{:.1}", 9.849f64)); + assert_eq!("9.9", format!("{:.1}", 9.851f64)); + assert_eq!("0", format!("{:.0}", 0.5f64)); + assert_eq!("1.23456789e6", format!("{:e}", 1234567.89f64)); + assert_eq!("1.23456789e3", format!("{:e}", 1234.56789f64)); + assert_eq!("1.23456789E6", format!("{:E}", 1234567.89f64)); + assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64)); + assert_eq!("0.0", format!("{:?}", 0.0f64)); + assert_eq!("1.01", format!("{:?}", 1.01f64)); + + let high_cutoff = 1e16_f64; + assert_eq!("1e16", format!("{:?}", high_cutoff)); + assert_eq!("-1e16", format!("{:?}", -high_cutoff)); + assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f64::EPSILON)))); + assert_eq!("-3.0", format!("{:?}", -3f64)); + assert_eq!("0.0001", format!("{:?}", 0.0001f64)); + assert_eq!("9e-5", format!("{:?}", 0.00009f64)); + assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f64)); + assert_eq!("1234.6", format!("{:.1?}", 1234.56789f64)); +} + +#[test] +fn test_format_f64_rounds_ties_to_even() { + assert_eq!("0", format!("{:.0}", 0.5f64)); + assert_eq!("2", format!("{:.0}", 1.5f64)); + assert_eq!("2", format!("{:.0}", 2.5f64)); + assert_eq!("4", format!("{:.0}", 3.5f64)); + assert_eq!("4", format!("{:.0}", 4.5f64)); + assert_eq!("6", format!("{:.0}", 5.5f64)); + assert_eq!("128", format!("{:.0}", 127.5f64)); + assert_eq!("128", format!("{:.0}", 128.5f64)); + assert_eq!("0.2", format!("{:.1}", 0.25f64)); + assert_eq!("0.8", format!("{:.1}", 0.75f64)); + assert_eq!("0.12", format!("{:.2}", 0.125f64)); + assert_eq!("0.88", format!("{:.2}", 0.875f64)); + assert_eq!("0.062", format!("{:.3}", 0.062f64)); + assert_eq!("-0", format!("{:.0}", -0.5f64)); + assert_eq!("-2", format!("{:.0}", -1.5f64)); + assert_eq!("-2", format!("{:.0}", -2.5f64)); + assert_eq!("-4", format!("{:.0}", -3.5f64)); + assert_eq!("-4", format!("{:.0}", -4.5f64)); + assert_eq!("-6", format!("{:.0}", -5.5f64)); + assert_eq!("-128", format!("{:.0}", -127.5f64)); + assert_eq!("-128", format!("{:.0}", -128.5f64)); + assert_eq!("-0.2", format!("{:.1}", -0.25f64)); + assert_eq!("-0.8", format!("{:.1}", -0.75f64)); + assert_eq!("-0.12", format!("{:.2}", -0.125f64)); + assert_eq!("-0.88", format!("{:.2}", -0.875f64)); + assert_eq!("-0.062", format!("{:.3}", -0.062f64)); + + assert_eq!("2e0", format!("{:.0e}", 1.5f64)); + assert_eq!("2e0", format!("{:.0e}", 2.5f64)); + assert_eq!("4e0", format!("{:.0e}", 3.5f64)); + assert_eq!("4e0", format!("{:.0e}", 4.5f64)); + assert_eq!("6e0", format!("{:.0e}", 5.5f64)); + assert_eq!("1.28e2", format!("{:.2e}", 127.5f64)); + assert_eq!("1.28e2", format!("{:.2e}", 128.5f64)); + assert_eq!("-2e0", format!("{:.0e}", -1.5f64)); + assert_eq!("-2e0", format!("{:.0e}", -2.5f64)); + assert_eq!("-4e0", format!("{:.0e}", -3.5f64)); + assert_eq!("-4e0", format!("{:.0e}", -4.5f64)); + assert_eq!("-6e0", format!("{:.0e}", -5.5f64)); + assert_eq!("-1.28e2", format!("{:.2e}", -127.5f64)); + assert_eq!("-1.28e2", format!("{:.2e}", -128.5f64)); + + assert_eq!("2E0", format!("{:.0E}", 1.5f64)); + assert_eq!("2E0", format!("{:.0E}", 2.5f64)); + assert_eq!("4E0", format!("{:.0E}", 3.5f64)); + assert_eq!("4E0", format!("{:.0E}", 4.5f64)); + assert_eq!("6E0", format!("{:.0E}", 5.5f64)); + assert_eq!("1.28E2", format!("{:.2E}", 127.5f64)); + assert_eq!("1.28E2", format!("{:.2E}", 128.5f64)); + assert_eq!("-2E0", format!("{:.0E}", -1.5f64)); + assert_eq!("-2E0", format!("{:.0E}", -2.5f64)); + assert_eq!("-4E0", format!("{:.0E}", -3.5f64)); + assert_eq!("-4E0", format!("{:.0E}", -4.5f64)); + assert_eq!("-6E0", format!("{:.0E}", -5.5f64)); + assert_eq!("-1.28E2", format!("{:.2E}", -127.5f64)); + assert_eq!("-1.28E2", format!("{:.2E}", -128.5f64)); +} + +#[test] +fn test_format_f32() { + assert_eq!("1", format!("{:.0}", 1.0f32)); + assert_eq!("9", format!("{:.0}", 9.4f32)); + assert_eq!("10", format!("{:.0}", 9.9f32)); + assert_eq!("9.8", format!("{:.1}", 9.849f32)); + assert_eq!("9.9", format!("{:.1}", 9.851f32)); + assert_eq!("0", format!("{:.0}", 0.5f32)); + assert_eq!("1.2345679e6", format!("{:e}", 1234567.89f32)); + assert_eq!("1.2345679e3", format!("{:e}", 1234.56789f32)); + assert_eq!("1.2345679E6", format!("{:E}", 1234567.89f32)); + assert_eq!("1.2345679E3", format!("{:E}", 1234.56789f32)); + assert_eq!("0.0", format!("{:?}", 0.0f32)); + assert_eq!("1.01", format!("{:?}", 1.01f32)); + + let high_cutoff = 1e16_f32; + assert_eq!("1e16", format!("{:?}", high_cutoff)); + assert_eq!("-1e16", format!("{:?}", -high_cutoff)); + assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f32::EPSILON)))); + assert_eq!("-3.0", format!("{:?}", -3f32)); + assert_eq!("0.0001", format!("{:?}", 0.0001f32)); + assert_eq!("9e-5", format!("{:?}", 0.00009f32)); + assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f32)); + assert_eq!("1234.6", format!("{:.1?}", 1234.56789f32)); +} + +#[test] +fn test_format_f32_rounds_ties_to_even() { + assert_eq!("0", format!("{:.0}", 0.5f32)); + assert_eq!("2", format!("{:.0}", 1.5f32)); + assert_eq!("2", format!("{:.0}", 2.5f32)); + assert_eq!("4", format!("{:.0}", 3.5f32)); + assert_eq!("4", format!("{:.0}", 4.5f32)); + assert_eq!("6", format!("{:.0}", 5.5f32)); + assert_eq!("128", format!("{:.0}", 127.5f32)); + assert_eq!("128", format!("{:.0}", 128.5f32)); + assert_eq!("0.2", format!("{:.1}", 0.25f32)); + assert_eq!("0.8", format!("{:.1}", 0.75f32)); + assert_eq!("0.12", format!("{:.2}", 0.125f32)); + assert_eq!("0.88", format!("{:.2}", 0.875f32)); + assert_eq!("0.062", format!("{:.3}", 0.062f32)); + assert_eq!("-0", format!("{:.0}", -0.5f32)); + assert_eq!("-2", format!("{:.0}", -1.5f32)); + assert_eq!("-2", format!("{:.0}", -2.5f32)); + assert_eq!("-4", format!("{:.0}", -3.5f32)); + assert_eq!("-4", format!("{:.0}", -4.5f32)); + assert_eq!("-6", format!("{:.0}", -5.5f32)); + assert_eq!("-128", format!("{:.0}", -127.5f32)); + assert_eq!("-128", format!("{:.0}", -128.5f32)); + assert_eq!("-0.2", format!("{:.1}", -0.25f32)); + assert_eq!("-0.8", format!("{:.1}", -0.75f32)); + assert_eq!("-0.12", format!("{:.2}", -0.125f32)); + assert_eq!("-0.88", format!("{:.2}", -0.875f32)); + assert_eq!("-0.062", format!("{:.3}", -0.062f32)); + + assert_eq!("2e0", format!("{:.0e}", 1.5f32)); + assert_eq!("2e0", format!("{:.0e}", 2.5f32)); + assert_eq!("4e0", format!("{:.0e}", 3.5f32)); + assert_eq!("4e0", format!("{:.0e}", 4.5f32)); + assert_eq!("6e0", format!("{:.0e}", 5.5f32)); + assert_eq!("1.28e2", format!("{:.2e}", 127.5f32)); + assert_eq!("1.28e2", format!("{:.2e}", 128.5f32)); + assert_eq!("-2e0", format!("{:.0e}", -1.5f32)); + assert_eq!("-2e0", format!("{:.0e}", -2.5f32)); + assert_eq!("-4e0", format!("{:.0e}", -3.5f32)); + assert_eq!("-4e0", format!("{:.0e}", -4.5f32)); + assert_eq!("-6e0", format!("{:.0e}", -5.5f32)); + assert_eq!("-1.28e2", format!("{:.2e}", -127.5f32)); + assert_eq!("-1.28e2", format!("{:.2e}", -128.5f32)); + + assert_eq!("2E0", format!("{:.0E}", 1.5f32)); + assert_eq!("2E0", format!("{:.0E}", 2.5f32)); + assert_eq!("4E0", format!("{:.0E}", 3.5f32)); + assert_eq!("4E0", format!("{:.0E}", 4.5f32)); + assert_eq!("6E0", format!("{:.0E}", 5.5f32)); + assert_eq!("1.28E2", format!("{:.2E}", 127.5f32)); + assert_eq!("1.28E2", format!("{:.2E}", 128.5f32)); + assert_eq!("-2E0", format!("{:.0E}", -1.5f32)); + assert_eq!("-2E0", format!("{:.0E}", -2.5f32)); + assert_eq!("-4E0", format!("{:.0E}", -3.5f32)); + assert_eq!("-4E0", format!("{:.0E}", -4.5f32)); + assert_eq!("-6E0", format!("{:.0E}", -5.5f32)); + assert_eq!("-1.28E2", format!("{:.2E}", -127.5f32)); + assert_eq!("-1.28E2", format!("{:.2E}", -128.5f32)); +} + +fn is_exponential(s: &str) -> bool { + s.contains("e") || s.contains("E") +} diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs new file mode 100644 index 00000000000..025c69c4f62 --- /dev/null +++ b/library/coretests/tests/fmt/mod.rs @@ -0,0 +1,82 @@ +mod builders; +mod float; +mod num; + +#[test] +fn test_format_flags() { + // No residual flags left by pointer formatting + let p = "".as_ptr(); + assert_eq!(format!("{:p} {:x}", p, 16), format!("{p:p} 10")); + + assert_eq!(format!("{: >3}", 'a'), " a"); +} + +#[test] +fn test_pointer_formats_data_pointer() { + let b: &[u8] = b""; + let s: &str = ""; + assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr())); + assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr())); +} + +#[test] +fn test_estimated_capacity() { + assert_eq!(format_args!("").estimated_capacity(), 0); + assert_eq!(format_args!("{}", { "" }).estimated_capacity(), 0); + assert_eq!(format_args!("Hello").estimated_capacity(), 5); + assert_eq!(format_args!("Hello, {}!", { "" }).estimated_capacity(), 16); + assert_eq!(format_args!("{}, hello!", { "World" }).estimated_capacity(), 0); + assert_eq!(format_args!("{}. 16-bytes piece", { "World" }).estimated_capacity(), 32); +} + +#[test] +fn pad_integral_resets() { + struct Bar; + + impl core::fmt::Display for Bar { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + "1".fmt(f)?; + f.pad_integral(true, "", "5")?; + "1".fmt(f) + } + } + + assert_eq!(format!("{Bar:<03}"), "1 0051 "); +} + +#[test] +fn test_maybe_uninit_short() { + // Ensure that the trimmed `MaybeUninit` Debug implementation doesn't break + let x = core::mem::MaybeUninit::new(0u32); + assert_eq!(format!("{x:?}"), "MaybeUninit"); +} + +#[test] +fn formatting_options_ctor() { + use core::fmt::FormattingOptions; + assert_eq!(FormattingOptions::new(), FormattingOptions::default()); +} + +#[test] +fn formatting_options_flags() { + use core::fmt::*; + for sign in [None, Some(Sign::Plus), Some(Sign::Minus)] { + for alternate in [true, false] { + for sign_aware_zero_pad in [true, false] { + for debug_as_hex in [None, Some(DebugAsHex::Lower), Some(DebugAsHex::Upper)] { + let mut formatting_options = FormattingOptions::new(); + formatting_options + .sign(sign) + .sign_aware_zero_pad(sign_aware_zero_pad) + .alternate(alternate) + .debug_as_hex(debug_as_hex); + + assert_eq!(formatting_options.get_sign(), sign); + assert_eq!(formatting_options.get_alternate(), alternate); + assert_eq!(formatting_options.get_sign_aware_zero_pad(), sign_aware_zero_pad); + assert_eq!(formatting_options.get_debug_as_hex(), debug_as_hex); + } + } + } + } +} diff --git a/library/coretests/tests/fmt/num.rs b/library/coretests/tests/fmt/num.rs new file mode 100644 index 00000000000..bc387a46ea7 --- /dev/null +++ b/library/coretests/tests/fmt/num.rs @@ -0,0 +1,240 @@ +#[test] +fn test_format_int() { + // Formatting integers should select the right implementation based off + // the type of the argument. Also, hex/octal/binary should be defined + // for integers, but they shouldn't emit the negative sign. + assert_eq!(format!("{}", 1isize), "1"); + assert_eq!(format!("{}", 1i8), "1"); + assert_eq!(format!("{}", 1i16), "1"); + assert_eq!(format!("{}", 1i32), "1"); + assert_eq!(format!("{}", 1i64), "1"); + assert_eq!(format!("{}", -1isize), "-1"); + assert_eq!(format!("{}", -1i8), "-1"); + assert_eq!(format!("{}", -1i16), "-1"); + assert_eq!(format!("{}", -1i32), "-1"); + assert_eq!(format!("{}", -1i64), "-1"); + assert_eq!(format!("{:?}", 1isize), "1"); + assert_eq!(format!("{:?}", 1i8), "1"); + assert_eq!(format!("{:?}", 1i16), "1"); + assert_eq!(format!("{:?}", 1i32), "1"); + assert_eq!(format!("{:?}", 1i64), "1"); + assert_eq!(format!("{:b}", 1isize), "1"); + assert_eq!(format!("{:b}", 1i8), "1"); + assert_eq!(format!("{:b}", 1i16), "1"); + assert_eq!(format!("{:b}", 1i32), "1"); + assert_eq!(format!("{:b}", 1i64), "1"); + assert_eq!(format!("{:x}", 1isize), "1"); + assert_eq!(format!("{:x}", 1i8), "1"); + assert_eq!(format!("{:x}", 1i16), "1"); + assert_eq!(format!("{:x}", 1i32), "1"); + assert_eq!(format!("{:x}", 1i64), "1"); + assert_eq!(format!("{:X}", 1isize), "1"); + assert_eq!(format!("{:X}", 1i8), "1"); + assert_eq!(format!("{:X}", 1i16), "1"); + assert_eq!(format!("{:X}", 1i32), "1"); + assert_eq!(format!("{:X}", 1i64), "1"); + assert_eq!(format!("{:o}", 1isize), "1"); + assert_eq!(format!("{:o}", 1i8), "1"); + assert_eq!(format!("{:o}", 1i16), "1"); + assert_eq!(format!("{:o}", 1i32), "1"); + assert_eq!(format!("{:o}", 1i64), "1"); + assert_eq!(format!("{:e}", 1isize), "1e0"); + assert_eq!(format!("{:e}", 1i8), "1e0"); + assert_eq!(format!("{:e}", 1i16), "1e0"); + assert_eq!(format!("{:e}", 1i32), "1e0"); + assert_eq!(format!("{:e}", 1i64), "1e0"); + assert_eq!(format!("{:E}", 1isize), "1E0"); + assert_eq!(format!("{:E}", 1i8), "1E0"); + assert_eq!(format!("{:E}", 1i16), "1E0"); + assert_eq!(format!("{:E}", 1i32), "1E0"); + assert_eq!(format!("{:E}", 1i64), "1E0"); + + assert_eq!(format!("{}", 1usize), "1"); + assert_eq!(format!("{}", 1u8), "1"); + assert_eq!(format!("{}", 1u16), "1"); + assert_eq!(format!("{}", 1u32), "1"); + assert_eq!(format!("{}", 1u64), "1"); + assert_eq!(format!("{:?}", 1usize), "1"); + assert_eq!(format!("{:?}", 1u8), "1"); + assert_eq!(format!("{:?}", 1u16), "1"); + assert_eq!(format!("{:?}", 1u32), "1"); + assert_eq!(format!("{:?}", 1u64), "1"); + assert_eq!(format!("{:b}", 1usize), "1"); + assert_eq!(format!("{:b}", 1u8), "1"); + assert_eq!(format!("{:b}", 1u16), "1"); + assert_eq!(format!("{:b}", 1u32), "1"); + assert_eq!(format!("{:b}", 1u64), "1"); + assert_eq!(format!("{:x}", 1usize), "1"); + assert_eq!(format!("{:x}", 1u8), "1"); + assert_eq!(format!("{:x}", 1u16), "1"); + assert_eq!(format!("{:x}", 1u32), "1"); + assert_eq!(format!("{:x}", 1u64), "1"); + assert_eq!(format!("{:X}", 1usize), "1"); + assert_eq!(format!("{:X}", 1u8), "1"); + assert_eq!(format!("{:X}", 1u16), "1"); + assert_eq!(format!("{:X}", 1u32), "1"); + assert_eq!(format!("{:X}", 1u64), "1"); + assert_eq!(format!("{:o}", 1usize), "1"); + assert_eq!(format!("{:o}", 1u8), "1"); + assert_eq!(format!("{:o}", 1u16), "1"); + assert_eq!(format!("{:o}", 1u32), "1"); + assert_eq!(format!("{:o}", 1u64), "1"); + assert_eq!(format!("{:e}", 1u8), "1e0"); + assert_eq!(format!("{:e}", 1u16), "1e0"); + assert_eq!(format!("{:e}", 1u32), "1e0"); + assert_eq!(format!("{:e}", 1u64), "1e0"); + assert_eq!(format!("{:E}", 1u8), "1E0"); + assert_eq!(format!("{:E}", 1u16), "1E0"); + assert_eq!(format!("{:E}", 1u32), "1E0"); + assert_eq!(format!("{:E}", 1u64), "1E0"); + + // Test a larger number + assert_eq!(format!("{:b}", 55), "110111"); + assert_eq!(format!("{:o}", 55), "67"); + assert_eq!(format!("{}", 55), "55"); + assert_eq!(format!("{:x}", 55), "37"); + assert_eq!(format!("{:X}", 55), "37"); + assert_eq!(format!("{:e}", 55), "5.5e1"); + assert_eq!(format!("{:E}", 55), "5.5E1"); + assert_eq!(format!("{:e}", 10000000000u64), "1e10"); + assert_eq!(format!("{:E}", 10000000000u64), "1E10"); + assert_eq!(format!("{:e}", 10000000001u64), "1.0000000001e10"); + assert_eq!(format!("{:E}", 10000000001u64), "1.0000000001E10"); +} + +#[test] +fn test_format_int_exp_limits() { + assert_eq!(format!("{:e}", i8::MIN), "-1.28e2"); + assert_eq!(format!("{:e}", i8::MAX), "1.27e2"); + assert_eq!(format!("{:e}", i16::MIN), "-3.2768e4"); + assert_eq!(format!("{:e}", i16::MAX), "3.2767e4"); + assert_eq!(format!("{:e}", i32::MIN), "-2.147483648e9"); + assert_eq!(format!("{:e}", i32::MAX), "2.147483647e9"); + assert_eq!(format!("{:e}", i64::MIN), "-9.223372036854775808e18"); + assert_eq!(format!("{:e}", i64::MAX), "9.223372036854775807e18"); + assert_eq!(format!("{:e}", i128::MIN), "-1.70141183460469231731687303715884105728e38"); + assert_eq!(format!("{:e}", i128::MAX), "1.70141183460469231731687303715884105727e38"); + + assert_eq!(format!("{:e}", u8::MAX), "2.55e2"); + assert_eq!(format!("{:e}", u16::MAX), "6.5535e4"); + assert_eq!(format!("{:e}", u32::MAX), "4.294967295e9"); + assert_eq!(format!("{:e}", u64::MAX), "1.8446744073709551615e19"); + assert_eq!(format!("{:e}", u128::MAX), "3.40282366920938463463374607431768211455e38"); +} + +#[test] +fn test_format_int_exp_precision() { + //test that float and integer match + let big_int: u32 = 314_159_265; + assert_eq!(format!("{big_int:.1e}"), format!("{:.1e}", f64::from(big_int))); + + // test adding precision + assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2"); + assert_eq!(format!("{:.10e}", i16::MIN), "-3.2768000000e4"); + assert_eq!(format!("{:.10e}", i32::MIN), "-2.1474836480e9"); + assert_eq!(format!("{:.20e}", i64::MIN), "-9.22337203685477580800e18"); + assert_eq!(format!("{:.40e}", i128::MIN), "-1.7014118346046923173168730371588410572800e38"); + + // test rounding + assert_eq!(format!("{:.1e}", i8::MIN), "-1.3e2"); + assert_eq!(format!("{:.1e}", i16::MIN), "-3.3e4"); + assert_eq!(format!("{:.1e}", i32::MIN), "-2.1e9"); + assert_eq!(format!("{:.1e}", i64::MIN), "-9.2e18"); + assert_eq!(format!("{:.1e}", i128::MIN), "-1.7e38"); + + // test huge precision + assert_eq!(format!("{:.1000e}", 1), format!("1.{}e0", "0".repeat(1000))); + //test zero precision + assert_eq!(format!("{:.0e}", 1), format!("1e0",)); + assert_eq!(format!("{:.0e}", 35), format!("4e1",)); + + // test padding with precision (and sign) + assert_eq!(format!("{:+10.3e}", 1), " +1.000e0"); + + // test precision remains correct when rounding to next power + #[cfg(miri)] // can't cover all of `i16` in Miri + let range = [i16::MIN, -1, 1, i16::MAX]; + #[cfg(not(miri))] + let range = i16::MIN..=i16::MAX; + for i in range { + for p in 0..=5 { + assert_eq!( + format!("{i:.p$e}"), + format!("{:.p$e}", f32::from(i)), + "integer {i} at precision {p}" + ); + } + } +} + +#[test] +fn test_format_int_zero() { + assert_eq!(format!("{}", 0), "0"); + assert_eq!(format!("{:?}", 0), "0"); + assert_eq!(format!("{:b}", 0), "0"); + assert_eq!(format!("{:o}", 0), "0"); + assert_eq!(format!("{:x}", 0), "0"); + assert_eq!(format!("{:X}", 0), "0"); + assert_eq!(format!("{:e}", 0), "0e0"); + assert_eq!(format!("{:E}", 0), "0E0"); + + assert_eq!(format!("{}", 0u32), "0"); + assert_eq!(format!("{:?}", 0u32), "0"); + assert_eq!(format!("{:b}", 0u32), "0"); + assert_eq!(format!("{:o}", 0u32), "0"); + assert_eq!(format!("{:x}", 0u32), "0"); + assert_eq!(format!("{:X}", 0u32), "0"); + assert_eq!(format!("{:e}", 0u32), "0e0"); + assert_eq!(format!("{:E}", 0u32), "0E0"); +} + +#[test] +fn test_format_int_flags() { + assert_eq!(format!("{:3}", 1), " 1"); + assert_eq!(format!("{:>3}", 1), " 1"); + assert_eq!(format!("{:>+3}", 1), " +1"); + assert_eq!(format!("{:<3}", 1), "1 "); + assert_eq!(format!("{:#}", 1), "1"); + assert_eq!(format!("{:#x}", 10), "0xa"); + assert_eq!(format!("{:#X}", 10), "0xA"); + assert_eq!(format!("{:#5x}", 10), " 0xa"); + assert_eq!(format!("{:#o}", 10), "0o12"); + assert_eq!(format!("{:08x}", 10), "0000000a"); + assert_eq!(format!("{:8x}", 10), " a"); + assert_eq!(format!("{:<8x}", 10), "a "); + assert_eq!(format!("{:>8x}", 10), " a"); + assert_eq!(format!("{:#08x}", 10), "0x00000a"); + assert_eq!(format!("{:08}", -10), "-0000010"); + assert_eq!(format!("{:x}", !0u8), "ff"); + assert_eq!(format!("{:X}", !0u8), "FF"); + assert_eq!(format!("{:b}", !0u8), "11111111"); + assert_eq!(format!("{:o}", !0u8), "377"); + assert_eq!(format!("{:#x}", !0u8), "0xff"); + assert_eq!(format!("{:#X}", !0u8), "0xFF"); + assert_eq!(format!("{:#b}", !0u8), "0b11111111"); + assert_eq!(format!("{:#o}", !0u8), "0o377"); +} + +#[test] +fn test_format_int_sign_padding() { + assert_eq!(format!("{:+5}", 1), " +1"); + assert_eq!(format!("{:+5}", -1), " -1"); + assert_eq!(format!("{:05}", 1), "00001"); + assert_eq!(format!("{:05}", -1), "-0001"); + assert_eq!(format!("{:+05}", 1), "+0001"); + assert_eq!(format!("{:+05}", -1), "-0001"); +} + +#[test] +fn test_format_int_twos_complement() { + assert_eq!(format!("{}", i8::MIN), "-128"); + assert_eq!(format!("{}", i16::MIN), "-32768"); + assert_eq!(format!("{}", i32::MIN), "-2147483648"); + assert_eq!(format!("{}", i64::MIN), "-9223372036854775808"); +} + +#[test] +fn test_format_debug_hex() { + assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]"); + assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]"); +} diff --git a/library/coretests/tests/future.rs b/library/coretests/tests/future.rs new file mode 100644 index 00000000000..ebfe5a0a66d --- /dev/null +++ b/library/coretests/tests/future.rs @@ -0,0 +1,127 @@ +use std::future::{Future, join}; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll, Wake}; +use std::thread; + +struct PollN { + val: usize, + polled: usize, + num: usize, +} + +impl Future for PollN { + type Output = usize; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.polled += 1; + + if self.polled == self.num { + return Poll::Ready(self.val); + } + + cx.waker().wake_by_ref(); + Poll::Pending + } +} + +fn poll_n(val: usize, num: usize) -> PollN { + PollN { val, num, polled: 0 } +} + +#[test] +fn test_join() { + block_on(async move { + let x = join!(async { 0 }).await; + assert_eq!(x, 0); + + let x = join!(async { 0 }, async { 1 }).await; + assert_eq!(x, (0, 1)); + + let x = join!(async { 0 }, async { 1 }, async { 2 }).await; + assert_eq!(x, (0, 1, 2)); + + let x = join!( + poll_n(0, 1), + poll_n(1, 5), + poll_n(2, 2), + poll_n(3, 1), + poll_n(4, 2), + poll_n(5, 3), + poll_n(6, 4), + poll_n(7, 1) + ) + .await; + assert_eq!(x, (0, 1, 2, 3, 4, 5, 6, 7)); + + let y = String::new(); + let x = join!(async { + println!("{y}"); + 1 + }) + .await; + assert_eq!(x, 1); + }); +} + +/// Tests that `join!(…)` behaves "like a function": evaluating its arguments +/// before applying any of its own logic. +/// +/// _e.g._, `join!(async_fn(&borrowed), …)` does not consume `borrowed`; +/// and `join!(opt_fut?, …)` does let that `?` refer to the callsite scope. +mod test_join_function_like_value_arg_semantics { + use super::*; + + async fn async_fn(_: impl Sized) {} + + // no need to _run_ this test, just to compile it. + fn _join_does_not_unnecessarily_move_mentioned_bindings() { + let not_copy = vec![()]; + let _ = join!(async_fn(¬_copy)); // should not move `not_copy` + let _ = ¬_copy; // OK + } + + #[test] + fn join_lets_control_flow_effects_such_as_try_flow_through() { + let maybe_fut = None; + if false { + *&mut { maybe_fut } = Some(async {}); + loop {} + } + assert!(Option::is_none(&try { join!(maybe_fut?, async { unreachable!() }) })); + } + + #[test] + fn join_is_able_to_handle_temporaries() { + let _ = join!(async_fn(&String::from("temporary"))); + let () = block_on(join!(async_fn(&String::from("temporary")))); + } +} + +fn block_on(fut: impl Future) { + struct Waker; + impl Wake for Waker { + fn wake(self: Arc) { + thread::current().unpark() + } + } + + let waker = Arc::new(Waker).into(); + let mut cx = Context::from_waker(&waker); + let mut fut = Box::pin(fut); + + loop { + match fut.as_mut().poll(&mut cx) { + Poll::Ready(_) => break, + Poll::Pending => thread::park(), + } + } +} + +// just tests by whether or not this compiles +fn _pending_impl_all_auto_traits() { + use std::panic::{RefUnwindSafe, UnwindSafe}; + fn all_auto_traits() {} + + all_auto_traits::>(); +} diff --git a/library/coretests/tests/hash/mod.rs b/library/coretests/tests/hash/mod.rs new file mode 100644 index 00000000000..1f10a4733b0 --- /dev/null +++ b/library/coretests/tests/hash/mod.rs @@ -0,0 +1,167 @@ +mod sip; + +use std::hash::{BuildHasher, Hash, Hasher}; +use std::ptr; +use std::rc::Rc; + +#[derive(Default)] +struct MyHasher { + hash: u64, +} + +impl Hasher for MyHasher { + fn write(&mut self, buf: &[u8]) { + for byte in buf { + self.hash += *byte as u64; + } + } + fn write_str(&mut self, s: &str) { + self.write(s.as_bytes()); + self.write_u8(0xFF); + } + fn finish(&self) -> u64 { + self.hash + } +} + +#[test] +fn test_writer_hasher() { + // FIXME(#110395) + /* const */ + fn hash(t: &T) -> u64 { + let mut s = MyHasher { hash: 0 }; + t.hash(&mut s); + s.finish() + } + + /* const { + // FIXME(fee1-dead): assert_eq + assert!(hash(&()) == 0); + assert!(hash(&5_u8) == 5); + assert!(hash(&5_u16) == 5); + assert!(hash(&5_u32) == 5); + + assert!(hash(&'a') == 97); + + let s: &str = "a"; + assert!(hash(&s) == 97 + 0xFF); + }; */ + + assert_eq!(hash(&()), 0); + + assert_eq!(hash(&5_u8), 5); + assert_eq!(hash(&5_u16), 5); + assert_eq!(hash(&5_u32), 5); + assert_eq!(hash(&5_u64), 5); + assert_eq!(hash(&5_usize), 5); + + assert_eq!(hash(&5_i8), 5); + assert_eq!(hash(&5_i16), 5); + assert_eq!(hash(&5_i32), 5); + assert_eq!(hash(&5_i64), 5); + assert_eq!(hash(&5_isize), 5); + + assert_eq!(hash(&false), 0); + assert_eq!(hash(&true), 1); + + assert_eq!(hash(&'a'), 97); + + let s: &str = "a"; + assert_eq!(hash(&s), 97 + 0xFF); + let s: Box = String::from("a").into_boxed_str(); + assert_eq!(hash(&s), 97 + 0xFF); + let s: Rc<&str> = Rc::new("a"); + assert_eq!(hash(&s), 97 + 0xFF); + let cs: &[u8] = &[1, 2, 3]; + assert_eq!(hash(&cs), 9); + let cs: Box<[u8]> = Box::new([1, 2, 3]); + assert_eq!(hash(&cs), 9); + let cs: Rc<[u8]> = Rc::new([1, 2, 3]); + assert_eq!(hash(&cs), 9); + + let ptr = ptr::without_provenance::(5_usize); + assert_eq!(hash(&ptr), 5); + + let ptr = ptr::without_provenance_mut::(5_usize); + assert_eq!(hash(&ptr), 5); + + if cfg!(miri) { + // Miri cannot hash pointers + return; + } + + let cs: &mut [u8] = &mut [1, 2, 3]; + let ptr = cs.as_ptr(); + let slice_ptr = cs as *const [u8]; + assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64); + + let slice_ptr = cs as *mut [u8]; + assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64); +} + +struct Custom { + hash: u64, +} + +#[derive(Default)] +struct CustomHasher { + output: u64, +} + +impl Hasher for CustomHasher { + fn finish(&self) -> u64 { + self.output + } + fn write(&mut self, _: &[u8]) { + panic!() + } + fn write_u64(&mut self, data: u64) { + self.output = data; + } +} + +impl Hash for Custom { + fn hash(&self, state: &mut H) { + state.write_u64(self.hash); + } +} + +#[test] +fn test_custom_state() { + // FIXME(#110395) + /* const */ + fn hash(t: &T) -> u64 { + let mut c = CustomHasher { output: 0 }; + t.hash(&mut c); + c.finish() + } + + assert_eq!(hash(&Custom { hash: 5 }), 5); + + // const { assert!(hash(&Custom { hash: 6 }) == 6) }; +} + +#[test] +fn test_indirect_hasher() { + let mut hasher = MyHasher { hash: 0 }; + { + let mut indirect_hasher: &mut dyn Hasher = &mut hasher; + 5u32.hash(&mut indirect_hasher); + } + assert_eq!(hasher.hash, 5); +} + +#[test] +fn test_build_hasher_dyn_compatible() { + use std::hash::{DefaultHasher, RandomState}; + + let _: &dyn BuildHasher = &RandomState::new(); +} + +// just tests by whether or not this compiles +fn _build_hasher_default_impl_all_auto_traits() { + use std::panic::{RefUnwindSafe, UnwindSafe}; + fn all_auto_traits() {} + + all_auto_traits::>(); +} diff --git a/library/coretests/tests/hash/sip.rs b/library/coretests/tests/hash/sip.rs new file mode 100644 index 00000000000..f79954f916b --- /dev/null +++ b/library/coretests/tests/hash/sip.rs @@ -0,0 +1,323 @@ +#![allow(deprecated)] + +use core::hash::{Hash, Hasher, SipHasher, SipHasher13}; +use core::{mem, slice}; + +// Hash just the bytes of the slice, without length prefix +struct Bytes<'a>(&'a [u8]); + +impl<'a> Hash for Bytes<'a> { + fn hash(&self, state: &mut H) { + let Bytes(v) = *self; + state.write(v); + } +} + +fn hash_with(mut st: H, x: &T) -> u64 { + x.hash(&mut st); + st.finish() +} + +fn hash(x: &T) -> u64 { + hash_with(SipHasher::new(), x) +} + +/* FIXME(#110395) +#[test] +const fn test_const_sip() { + let val1 = 0x45; + let val2 = 0xfeed; + + const fn const_hash(x: &T) -> u64 { + let mut st = SipHasher::new(); + x.hash(&mut st); + st.finish() + } + + assert!(const_hash(&(val1)) != const_hash(&(val2))); +} +*/ + +#[test] +#[allow(unused_must_use)] +fn test_siphash_1_3() { + let vecs: [[u8; 8]; 64] = [ + [0xdc, 0xc4, 0x0f, 0x05, 0x58, 0x01, 0xac, 0xab], + [0x93, 0xca, 0x57, 0x7d, 0xf3, 0x9b, 0xf4, 0xc9], + [0x4d, 0xd4, 0xc7, 0x4d, 0x02, 0x9b, 0xcb, 0x82], + [0xfb, 0xf7, 0xdd, 0xe7, 0xb8, 0x0a, 0xf8, 0x8b], + [0x28, 0x83, 0xd3, 0x88, 0x60, 0x57, 0x75, 0xcf], + [0x67, 0x3b, 0x53, 0x49, 0x2f, 0xd5, 0xf9, 0xde], + [0xa7, 0x22, 0x9f, 0xc5, 0x50, 0x2b, 0x0d, 0xc5], + [0x40, 0x11, 0xb1, 0x9b, 0x98, 0x7d, 0x92, 0xd3], + [0x8e, 0x9a, 0x29, 0x8d, 0x11, 0x95, 0x90, 0x36], + [0xe4, 0x3d, 0x06, 0x6c, 0xb3, 0x8e, 0xa4, 0x25], + [0x7f, 0x09, 0xff, 0x92, 0xee, 0x85, 0xde, 0x79], + [0x52, 0xc3, 0x4d, 0xf9, 0xc1, 0x18, 0xc1, 0x70], + [0xa2, 0xd9, 0xb4, 0x57, 0xb1, 0x84, 0xa3, 0x78], + [0xa7, 0xff, 0x29, 0x12, 0x0c, 0x76, 0x6f, 0x30], + [0x34, 0x5d, 0xf9, 0xc0, 0x11, 0xa1, 0x5a, 0x60], + [0x56, 0x99, 0x51, 0x2a, 0x6d, 0xd8, 0x20, 0xd3], + [0x66, 0x8b, 0x90, 0x7d, 0x1a, 0xdd, 0x4f, 0xcc], + [0x0c, 0xd8, 0xdb, 0x63, 0x90, 0x68, 0xf2, 0x9c], + [0x3e, 0xe6, 0x73, 0xb4, 0x9c, 0x38, 0xfc, 0x8f], + [0x1c, 0x7d, 0x29, 0x8d, 0xe5, 0x9d, 0x1f, 0xf2], + [0x40, 0xe0, 0xcc, 0xa6, 0x46, 0x2f, 0xdc, 0xc0], + [0x44, 0xf8, 0x45, 0x2b, 0xfe, 0xab, 0x92, 0xb9], + [0x2e, 0x87, 0x20, 0xa3, 0x9b, 0x7b, 0xfe, 0x7f], + [0x23, 0xc1, 0xe6, 0xda, 0x7f, 0x0e, 0x5a, 0x52], + [0x8c, 0x9c, 0x34, 0x67, 0xb2, 0xae, 0x64, 0xf4], + [0x79, 0x09, 0x5b, 0x70, 0x28, 0x59, 0xcd, 0x45], + [0xa5, 0x13, 0x99, 0xca, 0xe3, 0x35, 0x3e, 0x3a], + [0x35, 0x3b, 0xde, 0x4a, 0x4e, 0xc7, 0x1d, 0xa9], + [0x0d, 0xd0, 0x6c, 0xef, 0x02, 0xed, 0x0b, 0xfb], + [0xf4, 0xe1, 0xb1, 0x4a, 0xb4, 0x3c, 0xd9, 0x88], + [0x63, 0xe6, 0xc5, 0x43, 0xd6, 0x11, 0x0f, 0x54], + [0xbc, 0xd1, 0x21, 0x8c, 0x1f, 0xdd, 0x70, 0x23], + [0x0d, 0xb6, 0xa7, 0x16, 0x6c, 0x7b, 0x15, 0x81], + [0xbf, 0xf9, 0x8f, 0x7a, 0xe5, 0xb9, 0x54, 0x4d], + [0x3e, 0x75, 0x2a, 0x1f, 0x78, 0x12, 0x9f, 0x75], + [0x91, 0x6b, 0x18, 0xbf, 0xbe, 0xa3, 0xa1, 0xce], + [0x06, 0x62, 0xa2, 0xad, 0xd3, 0x08, 0xf5, 0x2c], + [0x57, 0x30, 0xc3, 0xa3, 0x2d, 0x1c, 0x10, 0xb6], + [0xa1, 0x36, 0x3a, 0xae, 0x96, 0x74, 0xf4, 0xb3], + [0x92, 0x83, 0x10, 0x7b, 0x54, 0x57, 0x6b, 0x62], + [0x31, 0x15, 0xe4, 0x99, 0x32, 0x36, 0xd2, 0xc1], + [0x44, 0xd9, 0x1a, 0x3f, 0x92, 0xc1, 0x7c, 0x66], + [0x25, 0x88, 0x13, 0xc8, 0xfe, 0x4f, 0x70, 0x65], + [0xa6, 0x49, 0x89, 0xc2, 0xd1, 0x80, 0xf2, 0x24], + [0x6b, 0x87, 0xf8, 0xfa, 0xed, 0x1c, 0xca, 0xc2], + [0x96, 0x21, 0x04, 0x9f, 0xfc, 0x4b, 0x16, 0xc2], + [0x23, 0xd6, 0xb1, 0x68, 0x93, 0x9c, 0x6e, 0xa1], + [0xfd, 0x14, 0x51, 0x8b, 0x9c, 0x16, 0xfb, 0x49], + [0x46, 0x4c, 0x07, 0xdf, 0xf8, 0x43, 0x31, 0x9f], + [0xb3, 0x86, 0xcc, 0x12, 0x24, 0xaf, 0xfd, 0xc6], + [0x8f, 0x09, 0x52, 0x0a, 0xd1, 0x49, 0xaf, 0x7e], + [0x9a, 0x2f, 0x29, 0x9d, 0x55, 0x13, 0xf3, 0x1c], + [0x12, 0x1f, 0xf4, 0xa2, 0xdd, 0x30, 0x4a, 0xc4], + [0xd0, 0x1e, 0xa7, 0x43, 0x89, 0xe9, 0xfa, 0x36], + [0xe6, 0xbc, 0xf0, 0x73, 0x4c, 0xb3, 0x8f, 0x31], + [0x80, 0xe9, 0xa7, 0x70, 0x36, 0xbf, 0x7a, 0xa2], + [0x75, 0x6d, 0x3c, 0x24, 0xdb, 0xc0, 0xbc, 0xb4], + [0x13, 0x15, 0xb7, 0xfd, 0x52, 0xd8, 0xf8, 0x23], + [0x08, 0x8a, 0x7d, 0xa6, 0x4d, 0x5f, 0x03, 0x8f], + [0x48, 0xf1, 0xe8, 0xb7, 0xe5, 0xd0, 0x9c, 0xd8], + [0xee, 0x44, 0xa6, 0xf7, 0xbc, 0xe6, 0xf4, 0xf6], + [0xf2, 0x37, 0x18, 0x0f, 0xd8, 0x9a, 0xc5, 0xae], + [0xe0, 0x94, 0x66, 0x4b, 0x15, 0xf6, 0xb2, 0xc3], + [0xa8, 0xb3, 0xbb, 0xb7, 0x62, 0x90, 0x19, 0x9d], + ]; + + let k0 = 0x_07_06_05_04_03_02_01_00; + let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; + let mut buf = Vec::new(); + let mut t = 0; + let mut state_inc = SipHasher13::new_with_keys(k0, k1); + + while t < 64 { + let vec = u64::from_le_bytes(vecs[t]); + let out = hash_with(SipHasher13::new_with_keys(k0, k1), &Bytes(&buf)); + assert_eq!(vec, out); + + let full = hash_with(SipHasher13::new_with_keys(k0, k1), &Bytes(&buf)); + let i = state_inc.finish(); + + assert_eq!(full, i); + assert_eq!(full, vec); + + buf.push(t as u8); + Hasher::write(&mut state_inc, &[t as u8]); + + t += 1; + } +} + +#[test] +#[allow(unused_must_use)] +fn test_siphash_2_4() { + let vecs: [[u8; 8]; 64] = [ + [0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72], + [0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74], + [0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d], + [0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85], + [0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf], + [0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18], + [0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb], + [0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab], + [0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93], + [0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e], + [0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a], + [0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4], + [0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75], + [0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14], + [0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7], + [0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1], + [0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f], + [0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69], + [0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b], + [0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb], + [0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe], + [0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0], + [0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93], + [0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8], + [0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8], + [0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc], + [0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17], + [0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f], + [0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde], + [0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6], + [0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad], + [0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32], + [0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71], + [0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7], + [0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12], + [0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15], + [0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31], + [0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02], + [0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca], + [0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a], + [0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e], + [0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad], + [0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18], + [0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4], + [0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9], + [0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9], + [0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb], + [0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0], + [0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6], + [0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7], + [0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee], + [0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1], + [0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a], + [0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81], + [0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f], + [0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24], + [0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7], + [0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea], + [0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60], + [0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66], + [0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c], + [0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f], + [0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5], + [0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95], + ]; + + let k0 = 0x_07_06_05_04_03_02_01_00; + let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; + let mut buf = Vec::new(); + let mut t = 0; + let mut state_inc = SipHasher::new_with_keys(k0, k1); + + while t < 64 { + let vec = u64::from_le_bytes(vecs[t]); + let out = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf)); + assert_eq!(vec, out); + + let full = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf)); + let i = state_inc.finish(); + + assert_eq!(full, i); + assert_eq!(full, vec); + + buf.push(t as u8); + Hasher::write(&mut state_inc, &[t as u8]); + + t += 1; + } +} + +#[test] +#[cfg(target_pointer_width = "32")] +fn test_hash_usize() { + let val = 0xdeadbeef_deadbeef_u64; + assert_ne!(hash(&(val as u64)), hash(&(val as usize))); + assert_eq!(hash(&(val as u32)), hash(&(val as usize))); +} + +#[test] +#[cfg(target_pointer_width = "64")] +fn test_hash_usize() { + let val = 0xdeadbeef_deadbeef_u64; + assert_eq!(hash(&(val as u64)), hash(&(val as usize))); + assert_ne!(hash(&(val as u32)), hash(&(val as usize))); +} + +#[test] +fn test_hash_idempotent() { + let val64 = 0xdeadbeef_deadbeef_u64; + assert_eq!(hash(&val64), hash(&val64)); + let val32 = 0xdeadbeef_u32; + assert_eq!(hash(&val32), hash(&val32)); +} + +#[test] +fn test_hash_no_bytes_dropped_64() { + let val = 0xdeadbeef_deadbeef_u64; + + assert_ne!(hash(&val), hash(&zero_byte(val, 0))); + assert_ne!(hash(&val), hash(&zero_byte(val, 1))); + assert_ne!(hash(&val), hash(&zero_byte(val, 2))); + assert_ne!(hash(&val), hash(&zero_byte(val, 3))); + assert_ne!(hash(&val), hash(&zero_byte(val, 4))); + assert_ne!(hash(&val), hash(&zero_byte(val, 5))); + assert_ne!(hash(&val), hash(&zero_byte(val, 6))); + assert_ne!(hash(&val), hash(&zero_byte(val, 7))); + + fn zero_byte(val: u64, byte: usize) -> u64 { + assert!(byte < 8); + val & !(0xff << (byte * 8)) + } +} + +#[test] +fn test_hash_no_bytes_dropped_32() { + let val = 0xdeadbeef_u32; + + assert_ne!(hash(&val), hash(&zero_byte(val, 0))); + assert_ne!(hash(&val), hash(&zero_byte(val, 1))); + assert_ne!(hash(&val), hash(&zero_byte(val, 2))); + assert_ne!(hash(&val), hash(&zero_byte(val, 3))); + + fn zero_byte(val: u32, byte: usize) -> u32 { + assert!(byte < 4); + val & !(0xff << (byte * 8)) + } +} + +#[test] +fn test_hash_no_concat_alias() { + let s = ("aa", "bb"); + let t = ("aabb", ""); + let u = ("a", "abb"); + + assert_ne!(s, t); + assert_ne!(t, u); + assert_ne!(hash(&s), hash(&t)); + assert_ne!(hash(&s), hash(&u)); + + let u = [1, 0, 0, 0]; + let v = (&u[..1], &u[1..3], &u[3..]); + let w = (&u[..], &u[4..4], &u[4..4]); + + assert_ne!(v, w); + assert_ne!(hash(&v), hash(&w)); +} + +#[test] +fn test_write_short_works() { + let test_usize = 0xd0c0b0a0usize; + let mut h1 = SipHasher::new(); + h1.write_usize(test_usize); + h1.write(b"bytes"); + h1.write(b"string"); + h1.write_u8(0xFFu8); + h1.write_u8(0x01u8); + let mut h2 = SipHasher::new(); + h2.write(unsafe { + slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::()) + }); + h2.write(b"bytes"); + h2.write(b"string"); + h2.write(&[0xFFu8, 0x01u8]); + assert_eq!(h1.finish(), h2.finish()); +} diff --git a/library/coretests/tests/intrinsics.rs b/library/coretests/tests/intrinsics.rs new file mode 100644 index 00000000000..744a6a0d2dd --- /dev/null +++ b/library/coretests/tests/intrinsics.rs @@ -0,0 +1,195 @@ +use core::any::TypeId; +use core::intrinsics::assume; + +#[test] +fn test_typeid_sized_types() { + struct X; + struct Y(#[allow(dead_code)] u32); + + assert_eq!(TypeId::of::(), TypeId::of::()); + assert_eq!(TypeId::of::(), TypeId::of::()); + assert!(TypeId::of::() != TypeId::of::()); +} + +#[test] +fn test_typeid_unsized_types() { + trait Z {} + struct X(#[allow(dead_code)] str); + struct Y(#[allow(dead_code)] dyn Z + 'static); + + assert_eq!(TypeId::of::(), TypeId::of::()); + assert_eq!(TypeId::of::(), TypeId::of::()); + assert!(TypeId::of::() != TypeId::of::()); +} + +// Check that `const_assume` feature allow `assume` intrinsic +// to be used in const contexts. +#[test] +fn test_assume_can_be_in_const_contexts() { + const unsafe fn foo(x: usize, y: usize) -> usize { + // SAFETY: the entire function is not safe, + // but it is just an example not used elsewhere. + unsafe { assume(y != 0) }; + x / y + } + let rs = unsafe { foo(42, 97) }; + assert_eq!(rs, 0); +} + +#[test] +const fn test_write_bytes_in_const_contexts() { + use core::intrinsics::write_bytes; + + const TEST: [u32; 3] = { + let mut arr = [1u32, 2, 3]; + unsafe { + write_bytes(arr.as_mut_ptr(), 0, 2); + } + arr + }; + + assert!(TEST[0] == 0); + assert!(TEST[1] == 0); + assert!(TEST[2] == 3); + + const TEST2: [u32; 3] = { + let mut arr = [1u32, 2, 3]; + unsafe { + write_bytes(arr.as_mut_ptr(), 1, 2); + } + arr + }; + + assert!(TEST2[0] == 16843009); + assert!(TEST2[1] == 16843009); + assert!(TEST2[2] == 3); +} + +#[test] +fn test_hints_in_const_contexts() { + use core::intrinsics::{likely, unlikely}; + + // In const contexts, they just return their argument. + const { + assert!(true == likely(true)); + assert!(false == likely(false)); + assert!(true == unlikely(true)); + assert!(false == unlikely(false)); + assert!(42u32 == core::intrinsics::black_box(42u32)); + assert!(42u32 == core::hint::black_box(42u32)); + } +} + +#[test] +fn test_const_allocate_at_runtime() { + use core::intrinsics::const_allocate; + unsafe { + assert!(const_allocate(4, 4).is_null()); + } +} + +#[test] +fn test_const_deallocate_at_runtime() { + use core::intrinsics::const_deallocate; + const X: &u32 = &42u32; + let x = &0u32; + unsafe { + const_deallocate(X as *const _ as *mut u8, 4, 4); // nop + const_deallocate(x as *const _ as *mut u8, 4, 4); // nop + const_deallocate(core::ptr::null_mut(), 1, 1); // nop + } +} + +#[test] +fn test_three_way_compare_in_const_contexts() { + use core::cmp::Ordering::{self, *}; + use core::intrinsics::three_way_compare; + + const UNSIGNED_LESS: Ordering = three_way_compare(123_u16, 456); + const UNSIGNED_EQUAL: Ordering = three_way_compare(456_u16, 456); + const UNSIGNED_GREATER: Ordering = three_way_compare(789_u16, 456); + const CHAR_LESS: Ordering = three_way_compare('A', 'B'); + const CHAR_EQUAL: Ordering = three_way_compare('B', 'B'); + const CHAR_GREATER: Ordering = three_way_compare('C', 'B'); + const SIGNED_LESS: Ordering = three_way_compare(123_i64, 456); + const SIGNED_EQUAL: Ordering = three_way_compare(456_i64, 456); + const SIGNED_GREATER: Ordering = three_way_compare(789_i64, 456); + + assert_eq!(UNSIGNED_LESS, Less); + assert_eq!(UNSIGNED_EQUAL, Equal); + assert_eq!(UNSIGNED_GREATER, Greater); + assert_eq!(CHAR_LESS, Less); + assert_eq!(CHAR_EQUAL, Equal); + assert_eq!(CHAR_GREATER, Greater); + assert_eq!(SIGNED_LESS, Less); + assert_eq!(SIGNED_EQUAL, Equal); + assert_eq!(SIGNED_GREATER, Greater); +} + +fn fallback_cma( + a: T, + b: T, + c: T, + d: T, +) -> (T::Unsigned, T) { + a.carrying_mul_add(b, c, d) +} + +#[test] +fn carrying_mul_add_fallback_u32() { + let r = fallback_cma::(0x9e37_79b9, 0x7f4a_7c15, 0xf39c_c060, 0x5ced_c834); + assert_eq!(r, (0x2087_20c1, 0x4eab_8e1d)); + let r = fallback_cma::(0x1082_276b, 0xf3a2_7251, 0xf86c_6a11, 0xd0c1_8e95); + assert_eq!(r, (0x7aa0_1781, 0x0fb6_0528)); +} + +#[test] +fn carrying_mul_add_fallback_i32() { + let r = fallback_cma::(-1, -1, -1, -1); + assert_eq!(r, (u32::MAX, -1)); + let r = fallback_cma::(1, -1, 1, 1); + assert_eq!(r, (1, 0)); +} + +#[test] +fn carrying_mul_add_fallback_u128() { + assert_eq!(fallback_cma::(u128::MAX, u128::MAX, 0, 0), (1, u128::MAX - 1)); + assert_eq!(fallback_cma::(1, 1, 1, 1), (3, 0)); + assert_eq!(fallback_cma::(0, 0, u128::MAX, u128::MAX), (u128::MAX - 1, 1)); + assert_eq!( + fallback_cma::(u128::MAX, u128::MAX, u128::MAX, u128::MAX), + (u128::MAX, u128::MAX), + ); + + let r = fallback_cma::( + 0x243f6a8885a308d313198a2e03707344, + 0xa4093822299f31d0082efa98ec4e6c89, + 0x452821e638d01377be5466cf34e90c6c, + 0xc0ac29b7c97c50dd3f84d5b5b5470917, + ); + assert_eq!(r, (0x8050ec20ed554e40338d277e00b674e7, 0x1739ee6cea07da409182d003859b59d8)); + let r = fallback_cma::( + 0x9216d5d98979fb1bd1310ba698dfb5ac, + 0x2ffd72dbd01adfb7b8e1afed6a267e96, + 0xba7c9045f12c7f9924a19947b3916cf7, + 0x0801f2e2858efc16636920d871574e69, + ); + assert_eq!(r, (0x185525545fdb2fefb502a3a602efd628, 0x1b62d35fe3bff6b566f99667ef7ebfd6)); +} + +#[test] +fn carrying_mul_add_fallback_i128() { + assert_eq!(fallback_cma::(-1, -1, 0, 0), (1, 0)); + let r = fallback_cma::(-1, -1, -1, -1); + assert_eq!(r, (u128::MAX, -1)); + let r = fallback_cma::(1, -1, 1, 1); + assert_eq!(r, (1, 0)); + assert_eq!( + fallback_cma::(i128::MAX, i128::MAX, i128::MAX, i128::MAX), + (u128::MAX, i128::MAX / 2), + ); + assert_eq!( + fallback_cma::(i128::MIN, i128::MIN, i128::MAX, i128::MAX), + (u128::MAX - 1, -(i128::MIN / 2)), + ); +} diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs new file mode 100644 index 00000000000..a5dd4e52577 --- /dev/null +++ b/library/coretests/tests/io/borrowed_buf.rs @@ -0,0 +1,167 @@ +use core::io::BorrowedBuf; +use core::mem::MaybeUninit; + +/// Test that BorrowedBuf has the correct numbers when created with new +#[test] +fn new() { + let buf: &mut [_] = &mut [0; 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + assert_eq!(rbuf.filled().len(), 0); + assert_eq!(rbuf.init_len(), 16); + assert_eq!(rbuf.capacity(), 16); + assert_eq!(rbuf.unfilled().capacity(), 16); +} + +/// Test that BorrowedBuf has the correct numbers when created with uninit +#[test] +fn uninit() { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + assert_eq!(rbuf.filled().len(), 0); + assert_eq!(rbuf.init_len(), 0); + assert_eq!(rbuf.capacity(), 16); + assert_eq!(rbuf.unfilled().capacity(), 16); +} + +#[test] +fn initialize_unfilled() { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + rbuf.unfilled().ensure_init(); + + assert_eq!(rbuf.init_len(), 16); +} + +#[test] +fn advance_filled() { + let buf: &mut [_] = &mut [0; 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + rbuf.unfilled().advance(1); + + assert_eq!(rbuf.filled().len(), 1); + assert_eq!(rbuf.unfilled().capacity(), 15); +} + +#[test] +fn clear() { + let buf: &mut [_] = &mut [255; 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + rbuf.unfilled().advance(16); + + assert_eq!(rbuf.filled().len(), 16); + assert_eq!(rbuf.unfilled().capacity(), 0); + + rbuf.clear(); + + assert_eq!(rbuf.filled().len(), 0); + assert_eq!(rbuf.unfilled().capacity(), 16); + + assert_eq!(rbuf.unfilled().init_ref(), [255; 16]); +} + +#[test] +fn set_init() { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + unsafe { + rbuf.set_init(8); + } + + assert_eq!(rbuf.init_len(), 8); + + rbuf.unfilled().advance(4); + + unsafe { + rbuf.set_init(2); + } + + assert_eq!(rbuf.init_len(), 8); + + unsafe { + rbuf.set_init(8); + } + + assert_eq!(rbuf.init_len(), 8); +} + +#[test] +fn append() { + let buf: &mut [_] = &mut [MaybeUninit::new(255); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + rbuf.unfilled().append(&[0; 8]); + + assert_eq!(rbuf.init_len(), 8); + assert_eq!(rbuf.filled().len(), 8); + assert_eq!(rbuf.filled(), [0; 8]); + + rbuf.clear(); + + rbuf.unfilled().append(&[1; 16]); + + assert_eq!(rbuf.init_len(), 16); + assert_eq!(rbuf.filled().len(), 16); + assert_eq!(rbuf.filled(), [1; 16]); +} + +#[test] +fn reborrow_written() { + let buf: &mut [_] = &mut [MaybeUninit::new(0); 32]; + let mut buf: BorrowedBuf<'_> = buf.into(); + + let mut cursor = buf.unfilled(); + cursor.append(&[1; 16]); + + let mut cursor2 = cursor.reborrow(); + cursor2.append(&[2; 16]); + + assert_eq!(cursor2.written(), 32); + assert_eq!(cursor.written(), 32); + + assert_eq!(buf.unfilled().written(), 0); + assert_eq!(buf.init_len(), 32); + assert_eq!(buf.filled().len(), 32); + let filled = buf.filled(); + assert_eq!(&filled[..16], [1; 16]); + assert_eq!(&filled[16..], [2; 16]); +} + +#[test] +fn cursor_set_init() { + let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let mut rbuf: BorrowedBuf<'_> = buf.into(); + + unsafe { + rbuf.unfilled().set_init(8); + } + + assert_eq!(rbuf.init_len(), 8); + assert_eq!(rbuf.unfilled().init_ref().len(), 8); + assert_eq!(rbuf.unfilled().init_mut().len(), 8); + assert_eq!(rbuf.unfilled().uninit_mut().len(), 8); + assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 16); + + rbuf.unfilled().advance(4); + + unsafe { + rbuf.unfilled().set_init(2); + } + + assert_eq!(rbuf.init_len(), 8); + + unsafe { + rbuf.unfilled().set_init(8); + } + + assert_eq!(rbuf.init_len(), 12); + assert_eq!(rbuf.unfilled().init_ref().len(), 8); + assert_eq!(rbuf.unfilled().init_mut().len(), 8); + assert_eq!(rbuf.unfilled().uninit_mut().len(), 4); + assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 12); +} diff --git a/library/coretests/tests/io/mod.rs b/library/coretests/tests/io/mod.rs new file mode 100644 index 00000000000..a24893a525a --- /dev/null +++ b/library/coretests/tests/io/mod.rs @@ -0,0 +1 @@ +mod borrowed_buf; diff --git a/library/coretests/tests/iter/adapters/array_chunks.rs b/library/coretests/tests/iter/adapters/array_chunks.rs new file mode 100644 index 00000000000..fb19a519f63 --- /dev/null +++ b/library/coretests/tests/iter/adapters/array_chunks.rs @@ -0,0 +1,179 @@ +use core::iter::{self}; + +use super::*; + +#[test] +fn test_iterator_array_chunks_infer() { + let xs = [1, 1, 2, -2, 6, 0, 3, 1]; + for [a, b, c] in xs.iter().copied().array_chunks() { + assert_eq!(a + b + c, 4); + } +} + +#[test] +fn test_iterator_array_chunks_clone_and_drop() { + let count = Cell::new(0); + let mut it = (0..5).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + assert_eq!(it.by_ref().count(), 1); + assert_eq!(count.get(), 3); + let mut it2 = it.clone(); + assert_eq!(count.get(), 3); + assert_eq!(it.into_remainder().unwrap().len(), 2); + assert_eq!(count.get(), 5); + assert!(it2.next().is_none()); + assert_eq!(it2.into_remainder().unwrap().len(), 2); + assert_eq!(count.get(), 7); +} + +#[test] +fn test_iterator_array_chunks_remainder() { + let mut it = (0..11).array_chunks::<4>(); + assert_eq!(it.next(), Some([0, 1, 2, 3])); + assert_eq!(it.next(), Some([4, 5, 6, 7])); + assert_eq!(it.next(), None); + assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]); +} + +#[test] +fn test_iterator_array_chunks_size_hint() { + let it = (0..6).array_chunks::<1>(); + assert_eq!(it.size_hint(), (6, Some(6))); + + let it = (0..6).array_chunks::<3>(); + assert_eq!(it.size_hint(), (2, Some(2))); + + let it = (0..6).array_chunks::<5>(); + assert_eq!(it.size_hint(), (1, Some(1))); + + let it = (0..6).array_chunks::<7>(); + assert_eq!(it.size_hint(), (0, Some(0))); + + let it = (1..).array_chunks::<2>(); + assert_eq!(it.size_hint(), (usize::MAX / 2, None)); + + let it = (1..).filter(|x| x % 2 != 0).array_chunks::<2>(); + assert_eq!(it.size_hint(), (0, None)); +} + +#[test] +fn test_iterator_array_chunks_count() { + let it = (0..6).array_chunks::<1>(); + assert_eq!(it.count(), 6); + + let it = (0..6).array_chunks::<3>(); + assert_eq!(it.count(), 2); + + let it = (0..6).array_chunks::<5>(); + assert_eq!(it.count(), 1); + + let it = (0..6).array_chunks::<7>(); + assert_eq!(it.count(), 0); + + let it = (0..6).filter(|x| x % 2 == 0).array_chunks::<2>(); + assert_eq!(it.count(), 1); + + let it = iter::empty::().array_chunks::<2>(); + assert_eq!(it.count(), 0); + + let it = [(); usize::MAX].iter().array_chunks::<2>(); + assert_eq!(it.count(), usize::MAX / 2); +} + +#[test] +fn test_iterator_array_chunks_next_and_next_back() { + let mut it = (0..11).array_chunks::<3>(); + assert_eq!(it.next(), Some([0, 1, 2])); + assert_eq!(it.next_back(), Some([6, 7, 8])); + assert_eq!(it.next(), Some([3, 4, 5])); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.into_remainder().unwrap().as_slice(), &[9, 10]); +} + +#[test] +fn test_iterator_array_chunks_rev_remainder() { + let mut it = (0..11).array_chunks::<4>(); + { + let mut it = it.by_ref().rev(); + assert_eq!(it.next(), Some([4, 5, 6, 7])); + assert_eq!(it.next(), Some([0, 1, 2, 3])); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); + } + assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]); +} + +#[test] +fn test_iterator_array_chunks_try_fold() { + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result: Result<_, ()> = it.by_ref().try_fold(0, |acc, _item| Ok(acc + 1)); + assert_eq!(result, Ok(3)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 10); + + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result = it.by_ref().try_fold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) }); + assert_eq!(result, Err(2)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 9); +} + +#[test] +fn test_iterator_array_chunks_fold() { + let result = (1..11).array_chunks::<3>().fold(0, |acc, [a, b, c]| { + assert_eq!(acc + 1, a); + assert_eq!(acc + 2, b); + assert_eq!(acc + 3, c); + acc + 3 + }); + assert_eq!(result, 9); + + let count = Cell::new(0); + let result = + (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().fold(0, |acc, _item| acc + 1); + assert_eq!(result, 3); + // fold impls may or may not process the remainder + assert!(count.get() <= 10 && count.get() >= 9); +} + +#[test] +fn test_iterator_array_chunks_try_rfold() { + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result: Result<_, ()> = it.try_rfold(0, |acc, _item| Ok(acc + 1)); + assert_eq!(result, Ok(3)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 10); + + let count = Cell::new(0); + let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>(); + let result = it.try_rfold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) }); + assert_eq!(result, Err(2)); + assert_eq!(count.get(), 9); + drop(it); + assert_eq!(count.get(), 10); +} + +#[test] +fn test_iterator_array_chunks_rfold() { + let result = (1..11).array_chunks::<3>().rfold(0, |acc, [a, b, c]| { + assert_eq!(10 - (acc + 1), c); + assert_eq!(10 - (acc + 2), b); + assert_eq!(10 - (acc + 3), a); + acc + 3 + }); + assert_eq!(result, 9); + + let count = Cell::new(0); + let result = + (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().rfold(0, |acc, _item| acc + 1); + assert_eq!(result, 3); + assert_eq!(count.get(), 10); +} diff --git a/library/coretests/tests/iter/adapters/by_ref_sized.rs b/library/coretests/tests/iter/adapters/by_ref_sized.rs new file mode 100644 index 00000000000..a9c066f0e8c --- /dev/null +++ b/library/coretests/tests/iter/adapters/by_ref_sized.rs @@ -0,0 +1,20 @@ +use core::iter::*; + +#[test] +fn test_iterator_by_ref_sized() { + let a = ['a', 'b', 'c', 'd']; + + let mut s = String::from("Z"); + let mut it = a.iter().copied(); + ByRefSized(&mut it).take(2).for_each(|x| s.push(x)); + assert_eq!(s, "Zab"); + ByRefSized(&mut it).fold((), |(), x| s.push(x)); + assert_eq!(s, "Zabcd"); + + let mut s = String::from("Z"); + let mut it = a.iter().copied(); + ByRefSized(&mut it).rev().take(2).for_each(|x| s.push(x)); + assert_eq!(s, "Zdc"); + ByRefSized(&mut it).rfold((), |(), x| s.push(x)); + assert_eq!(s, "Zdcba"); +} diff --git a/library/coretests/tests/iter/adapters/chain.rs b/library/coretests/tests/iter/adapters/chain.rs new file mode 100644 index 00000000000..1b2c026ee1e --- /dev/null +++ b/library/coretests/tests/iter/adapters/chain.rs @@ -0,0 +1,293 @@ +use core::iter::*; +use core::num::NonZero; + +use super::*; + +#[test] +fn test_chain() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + assert_eq!(Vec::from_iter(chain(xs, ys)), expected); +} + +#[test] +fn test_iterator_chain() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + let it = xs.iter().chain(&ys); + let mut i = 0; + for &x in it { + assert_eq!(x, expected[i]); + i += 1; + } + assert_eq!(i, expected.len()); + + let ys = (30..).step_by(10).take(4); + let it = xs.iter().cloned().chain(ys); + let mut i = 0; + for x in it { + assert_eq!(x, expected[i]); + i += 1; + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_iterator_chain_advance_by() { + fn test_chain(xs: &[i32], ys: &[i32]) { + let len = xs.len() + ys.len(); + + for i in 0..xs.len() { + let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.next(), Some(&xs[i])); + assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (len - i - 1)).unwrap())); + assert_eq!(iter.advance_by(0), Ok(())); + } + + for i in 0..ys.len() { + let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); + assert_eq!(iter.advance_by(xs.len() + i), Ok(())); + assert_eq!(iter.next(), Some(&ys[i])); + assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (ys.len() - i - 1)).unwrap())); + assert_eq!(iter.advance_by(0), Ok(())); + } + + let mut iter = xs.iter().chain(ys); + assert_eq!(iter.advance_by(len), Ok(())); + assert_eq!(iter.next(), None); + assert_eq!(iter.advance_by(0), Ok(())); + + let mut iter = xs.iter().chain(ys); + assert_eq!(iter.advance_by(len + 1), Err(NonZero::new(1).unwrap())); + assert_eq!(iter.advance_by(0), Ok(())); + } + + test_chain(&[], &[]); + test_chain(&[], &[0, 1, 2, 3, 4, 5]); + test_chain(&[0, 1, 2, 3, 4, 5], &[]); + test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); +} + +#[test] +fn test_iterator_chain_advance_back_by() { + fn test_chain(xs: &[i32], ys: &[i32]) { + let len = xs.len() + ys.len(); + + for i in 0..ys.len() { + let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1])); + assert_eq!(iter.advance_back_by(100), Err(NonZero::new(100 - (len - i - 1)).unwrap())); + assert_eq!(iter.advance_back_by(0), Ok(())); + } + + for i in 0..xs.len() { + let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); + assert_eq!(iter.advance_back_by(ys.len() + i), Ok(())); + assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1])); + assert_eq!( + iter.advance_back_by(100), + Err(NonZero::new(100 - (xs.len() - i - 1)).unwrap()) + ); + assert_eq!(iter.advance_back_by(0), Ok(())); + } + + let mut iter = xs.iter().chain(ys); + assert_eq!(iter.advance_back_by(len), Ok(())); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.advance_back_by(0), Ok(())); + + let mut iter = xs.iter().chain(ys); + assert_eq!(iter.advance_back_by(len + 1), Err(NonZero::new(1).unwrap())); + assert_eq!(iter.advance_back_by(0), Ok(())); + } + + test_chain(&[], &[]); + test_chain(&[], &[0, 1, 2, 3, 4, 5]); + test_chain(&[0, 1, 2, 3, 4, 5], &[]); + test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); +} + +#[test] +fn test_iterator_chain_nth() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let zs = []; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + for (i, x) in expected.iter().enumerate() { + assert_eq!(Some(x), xs.iter().chain(&ys).nth(i)); + } + assert_eq!(zs.iter().chain(&xs).nth(0), Some(&0)); + + let mut it = xs.iter().chain(&zs); + assert_eq!(it.nth(5), Some(&5)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_iterator_chain_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let zs = []; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + for (i, x) in expected.iter().rev().enumerate() { + assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i)); + } + assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5)); + + let mut it = xs.iter().chain(&zs); + assert_eq!(it.nth_back(5), Some(&0)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_iterator_chain_last() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let zs = []; + assert_eq!(xs.iter().chain(&ys).last(), Some(&60)); + assert_eq!(zs.iter().chain(&ys).last(), Some(&60)); + assert_eq!(ys.iter().chain(&zs).last(), Some(&60)); + assert_eq!(zs.iter().chain(&zs).last(), None); +} + +#[test] +fn test_iterator_chain_count() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let zs = []; + assert_eq!(xs.iter().chain(&ys).count(), 10); + assert_eq!(zs.iter().chain(&ys).count(), 4); +} + +#[test] +fn test_iterator_chain_find() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let mut iter = xs.iter().chain(&ys); + assert_eq!(iter.find(|&&i| i == 4), Some(&4)); + assert_eq!(iter.next(), Some(&5)); + assert_eq!(iter.find(|&&i| i == 40), Some(&40)); + assert_eq!(iter.next(), Some(&50)); + assert_eq!(iter.find(|&&i| i == 100), None); + assert_eq!(iter.next(), None); +} + +#[test] +fn test_iterator_chain_size_hint() { + // this chains an iterator of length 0 with an iterator of length 1, + // so after calling `.next()` once, the iterator is empty and the + // state is `ChainState::Back`. `.size_hint()` should now disregard + // the size hint of the left iterator + let mut iter = Toggle { is_empty: true }.chain(once(())); + assert_eq!(iter.next(), Some(())); + assert_eq!(iter.size_hint(), (0, Some(0))); + + let mut iter = once(()).chain(Toggle { is_empty: true }); + assert_eq!(iter.next_back(), Some(())); + assert_eq!(iter.size_hint(), (0, Some(0))); +} + +#[test] +fn test_iterator_chain_unfused() { + // Chain shouldn't be fused in its second iterator, depending on direction + let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true }); + assert!(iter.next().is_none()); + assert!(iter.next().is_some()); + assert!(iter.next().is_none()); + + let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty())); + assert!(iter.next_back().is_none()); + assert!(iter.next_back().is_some()); + assert!(iter.next_back().is_none()); +} + +#[test] +fn test_chain_fold() { + let xs = [1, 2, 3]; + let ys = [1, 2, 0]; + + let mut iter = xs.iter().chain(&ys); + iter.next(); + let mut result = Vec::new(); + iter.fold((), |(), &elt| result.push(elt)); + assert_eq!(&[2, 3, 1, 2, 0], &result[..]); +} + +#[test] +fn test_chain_try_folds() { + let c = || (0..10).chain(10..20); + + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!(c().try_fold(7, f), (0..20).try_fold(7, f)); + assert_eq!(c().try_rfold(7, f), (0..20).rev().try_fold(7, f)); + + let mut iter = c(); + assert_eq!(iter.position(|x| x == 5), Some(5)); + assert_eq!(iter.next(), Some(6), "stopped in front, state Both"); + assert_eq!(iter.position(|x| x == 13), Some(6)); + assert_eq!(iter.next(), Some(14), "stopped in back, state Back"); + assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((15..20).sum())); + + let mut iter = c().rev(); // use rev to access try_rfold + assert_eq!(iter.position(|x| x == 15), Some(4)); + assert_eq!(iter.next(), Some(14), "stopped in back, state Both"); + assert_eq!(iter.position(|x| x == 5), Some(8)); + assert_eq!(iter.next(), Some(4), "stopped in front, state Front"); + assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((0..4).sum())); + + let mut iter = c(); + iter.by_ref().rev().nth(14); // skip the last 15, ending in state Front + assert_eq!(iter.try_fold(7, f), (0..5).try_fold(7, f)); + + let mut iter = c(); + iter.nth(14); // skip the first 15, ending in state Back + assert_eq!(iter.try_rfold(7, f), (15..20).try_rfold(7, f)); +} + +#[test] +fn test_double_ended_chain() { + let xs = [1, 2, 3, 4, 5]; + let ys = [7, 9, 11]; + let mut it = xs.iter().chain(&ys).rev(); + assert_eq!(it.next().unwrap(), &11); + assert_eq!(it.next().unwrap(), &9); + assert_eq!(it.next_back().unwrap(), &1); + assert_eq!(it.next_back().unwrap(), &2); + assert_eq!(it.next_back().unwrap(), &3); + assert_eq!(it.next_back().unwrap(), &4); + assert_eq!(it.next_back().unwrap(), &5); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back(), None); + + // test that .chain() is well behaved with an unfused iterator + struct CrazyIterator(bool); + impl CrazyIterator { + fn new() -> CrazyIterator { + CrazyIterator(false) + } + } + impl Iterator for CrazyIterator { + type Item = i32; + fn next(&mut self) -> Option { + if self.0 { + Some(99) + } else { + self.0 = true; + None + } + } + } + + impl DoubleEndedIterator for CrazyIterator { + fn next_back(&mut self) -> Option { + self.next() + } + } + + assert_eq!(CrazyIterator::new().chain(0..10).rev().last(), Some(0)); + assert!((0..10).chain(CrazyIterator::new()).rev().any(|i| i == 0)); +} diff --git a/library/coretests/tests/iter/adapters/cloned.rs b/library/coretests/tests/iter/adapters/cloned.rs new file mode 100644 index 00000000000..78babb7feab --- /dev/null +++ b/library/coretests/tests/iter/adapters/cloned.rs @@ -0,0 +1,52 @@ +use core::iter::*; + +#[test] +fn test_cloned() { + let xs = [2, 4, 6, 8]; + + let mut it = xs.iter().cloned(); + assert_eq!(it.len(), 4); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.len(), 3); + assert_eq!(it.next(), Some(4)); + assert_eq!(it.len(), 2); + assert_eq!(it.next_back(), Some(8)); + assert_eq!(it.len(), 1); + assert_eq!(it.next_back(), Some(6)); + assert_eq!(it.len(), 0); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_cloned_side_effects() { + let mut count = 0; + { + let iter = [1, 2, 3] + .iter() + .map(|x| { + count += 1; + x + }) + .cloned() + .zip(&[1]); + for _ in iter {} + } + assert_eq!(count, 2); +} + +#[test] +fn test_cloned_try_folds() { + let a = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + let f = &|acc, x| i32::checked_add(2 * acc, x); + let f_ref = &|acc, &x| i32::checked_add(2 * acc, x); + assert_eq!(a.iter().cloned().try_fold(7, f), a.iter().try_fold(7, f_ref)); + assert_eq!(a.iter().cloned().try_rfold(7, f), a.iter().try_rfold(7, f_ref)); + + let a = [10, 20, 30, 40, 100, 60, 70, 80, 90]; + let mut iter = a.iter().cloned(); + assert_eq!(iter.try_fold(0_i8, |acc, x| acc.checked_add(x)), None); + assert_eq!(iter.next(), Some(60)); + let mut iter = a.iter().cloned(); + assert_eq!(iter.try_rfold(0_i8, |acc, x| acc.checked_add(x)), None); + assert_eq!(iter.next_back(), Some(70)); +} diff --git a/library/coretests/tests/iter/adapters/copied.rs b/library/coretests/tests/iter/adapters/copied.rs new file mode 100644 index 00000000000..b12f2035dc1 --- /dev/null +++ b/library/coretests/tests/iter/adapters/copied.rs @@ -0,0 +1,18 @@ +use core::iter::*; + +#[test] +fn test_copied() { + let xs = [2, 4, 6, 8]; + + let mut it = xs.iter().copied(); + assert_eq!(it.len(), 4); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.len(), 3); + assert_eq!(it.next(), Some(4)); + assert_eq!(it.len(), 2); + assert_eq!(it.next_back(), Some(8)); + assert_eq!(it.len(), 1); + assert_eq!(it.next_back(), Some(6)); + assert_eq!(it.len(), 0); + assert_eq!(it.next_back(), None); +} diff --git a/library/coretests/tests/iter/adapters/cycle.rs b/library/coretests/tests/iter/adapters/cycle.rs new file mode 100644 index 00000000000..8831c09b48b --- /dev/null +++ b/library/coretests/tests/iter/adapters/cycle.rs @@ -0,0 +1,31 @@ +use core::iter::*; + +#[test] +fn test_cycle() { + let cycle_len = 3; + let it = (0..).step_by(1).take(cycle_len).cycle(); + assert_eq!(it.size_hint(), (usize::MAX, None)); + for (i, x) in it.take(100).enumerate() { + assert_eq!(i % cycle_len, x); + } + + let mut it = (0..).step_by(1).take(0).cycle(); + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None); + + assert_eq!(empty::().cycle().fold(0, |acc, x| acc + x), 0); + + assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4); + + assert_eq!((0..10).cycle().take(5).sum::(), 10); + assert_eq!((0..10).cycle().take(15).sum::(), 55); + assert_eq!((0..10).cycle().take(25).sum::(), 100); + + let mut iter = (0..10).cycle(); + iter.nth(14); + assert_eq!(iter.take(8).sum::(), 38); + + let mut iter = (0..10).cycle(); + iter.nth(9); + assert_eq!(iter.take(3).sum::(), 3); +} diff --git a/library/coretests/tests/iter/adapters/enumerate.rs b/library/coretests/tests/iter/adapters/enumerate.rs new file mode 100644 index 00000000000..b57d51c077e --- /dev/null +++ b/library/coretests/tests/iter/adapters/enumerate.rs @@ -0,0 +1,122 @@ +use core::iter::*; +use core::num::NonZero; + +#[test] +fn test_iterator_enumerate() { + let xs = [0, 1, 2, 3, 4, 5]; + let it = xs.iter().enumerate(); + for (i, &x) in it { + assert_eq!(i, x); + } +} + +#[test] +fn test_iterator_enumerate_nth() { + let xs = [0, 1, 2, 3, 4, 5]; + for (i, &x) in xs.iter().enumerate() { + assert_eq!(i, x); + } + + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth(0) { + assert_eq!(i, x); + } + + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth(1) { + assert_eq!(i, x); + } + + let (i, &x) = xs.iter().enumerate().nth(3).unwrap(); + assert_eq!(i, x); + assert_eq!(i, 3); +} + +#[test] +fn test_iterator_enumerate_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth_back(0) { + assert_eq!(i, x); + } + + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth_back(1) { + assert_eq!(i, x); + } + + let (i, &x) = xs.iter().enumerate().nth_back(3).unwrap(); + assert_eq!(i, x); + assert_eq!(i, 2); +} + +#[test] +fn test_iterator_enumerate_count() { + let xs = [0, 1, 2, 3, 4, 5]; + assert_eq!(xs.iter().enumerate().count(), 6); +} + +#[test] +fn test_iterator_enumerate_advance_by() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().enumerate(); + assert_eq!(it.advance_by(0), Ok(())); + assert_eq!(it.next(), Some((0, &0))); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.next(), Some((2, &2))); + assert_eq!(it.advance_by(2), Ok(())); + assert_eq!(it.next(), Some((5, &5))); + assert_eq!(it.advance_by(1), Err(NonZero::new(1).unwrap())); + assert_eq!(it.next(), None); +} + +#[test] +fn test_iterator_enumerate_fold() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().enumerate(); + // steal a couple to get an interesting offset + assert_eq!(it.next(), Some((0, &0))); + assert_eq!(it.next(), Some((1, &1))); + let i = it.fold(2, |i, (j, &x)| { + assert_eq!(i, j); + assert_eq!(x, xs[j]); + i + 1 + }); + assert_eq!(i, xs.len()); + + let mut it = xs.iter().enumerate(); + assert_eq!(it.next(), Some((0, &0))); + let i = it.rfold(xs.len() - 1, |i, (j, &x)| { + assert_eq!(i, j); + assert_eq!(x, xs[j]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_enumerate_try_folds() { + let f = &|acc, (i, x)| usize::checked_add(2 * acc, x / (i + 1) + i); + assert_eq!((9..18).enumerate().try_fold(7, f), (0..9).map(|i| (i, i + 9)).try_fold(7, f)); + assert_eq!((9..18).enumerate().try_rfold(7, f), (0..9).map(|i| (i, i + 9)).try_rfold(7, f)); + + let mut iter = (100..200).enumerate(); + let f = &|acc, (i, x)| u8::checked_add(acc, u8::checked_div(x, i as u8 + 1)?); + assert_eq!(iter.try_fold(0, f), None); + assert_eq!(iter.next(), Some((7, 107))); + assert_eq!(iter.try_rfold(0, f), None); + assert_eq!(iter.next_back(), Some((11, 111))); +} + +#[test] +fn test_double_ended_enumerate() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut it = xs.iter().cloned().enumerate(); + assert_eq!(it.next(), Some((0, 1))); + assert_eq!(it.next(), Some((1, 2))); + assert_eq!(it.next_back(), Some((5, 6))); + assert_eq!(it.next_back(), Some((4, 5))); + assert_eq!(it.next_back(), Some((3, 4))); + assert_eq!(it.next_back(), Some((2, 3))); + assert_eq!(it.next(), None); +} diff --git a/library/coretests/tests/iter/adapters/filter.rs b/library/coretests/tests/iter/adapters/filter.rs new file mode 100644 index 00000000000..167851e3333 --- /dev/null +++ b/library/coretests/tests/iter/adapters/filter.rs @@ -0,0 +1,65 @@ +use core::iter::*; +use std::rc::Rc; + +#[test] +fn test_iterator_filter_count() { + let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5); +} + +#[test] +fn test_iterator_filter_fold() { + let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let ys = [0, 2, 4, 6, 8]; + let it = xs.iter().filter(|&&x| x % 2 == 0); + let i = it.fold(0, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let it = xs.iter().filter(|&&x| x % 2 == 0); + let i = it.rfold(ys.len(), |i, &x| { + assert_eq!(x, ys[i - 1]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_filter_try_folds() { + fn p(&x: &i32) -> bool { + 0 <= x && x < 10 + } + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((-10..20).filter(p).try_fold(7, f), (0..10).try_fold(7, f)); + assert_eq!((-10..20).filter(p).try_rfold(7, f), (0..10).try_rfold(7, f)); + + let mut iter = (0..40).filter(|&x| x % 2 == 1); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(25)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(31)); +} + +#[test] +fn test_double_ended_filter() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut it = xs.iter().filter(|&x| *x & 1 == 0); + assert_eq!(it.next_back().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &4); + assert_eq!(it.next().unwrap(), &2); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_next_chunk_does_not_leak() { + let drop_witness: [_; 5] = std::array::from_fn(|_| Rc::new(())); + + let v = (0..5).map(|i| drop_witness[i].clone()).collect::>(); + let _ = v.into_iter().filter(|_| false).next_chunk::<1>(); + + for ref w in drop_witness { + assert_eq!(Rc::strong_count(w), 1); + } +} diff --git a/library/coretests/tests/iter/adapters/filter_map.rs b/library/coretests/tests/iter/adapters/filter_map.rs new file mode 100644 index 00000000000..46738eda63f --- /dev/null +++ b/library/coretests/tests/iter/adapters/filter_map.rs @@ -0,0 +1,50 @@ +use core::iter::*; + +#[test] +fn test_filter_map() { + let it = (0..).step_by(1).take(10).filter_map(|x| if x % 2 == 0 { Some(x * x) } else { None }); + assert_eq!(it.collect::>(), [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]); +} + +#[test] +fn test_filter_map_fold() { + let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let ys = [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]; + let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None }); + let i = it.fold(0, |i, x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None }); + let i = it.rfold(ys.len(), |i, x| { + assert_eq!(x, ys[i - 1]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_filter_map_try_folds() { + let mp = &|x| if 0 <= x && x < 10 { Some(x * 2) } else { None }; + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((-9..20).filter_map(mp).try_fold(7, f), (0..10).map(|x| 2 * x).try_fold(7, f)); + assert_eq!((-9..20).filter_map(mp).try_rfold(7, f), (0..10).map(|x| 2 * x).try_rfold(7, f)); + + let mut iter = (0..40).filter_map(|x| if x % 2 == 1 { None } else { Some(x * 2 + 10) }); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(38)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(78)); +} + +#[test] +fn test_double_ended_filter_map() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None }); + assert_eq!(it.next_back().unwrap(), 12); + assert_eq!(it.next_back().unwrap(), 8); + assert_eq!(it.next().unwrap(), 4); + assert_eq!(it.next_back(), None); +} diff --git a/library/coretests/tests/iter/adapters/flat_map.rs b/library/coretests/tests/iter/adapters/flat_map.rs new file mode 100644 index 00000000000..ee945e69801 --- /dev/null +++ b/library/coretests/tests/iter/adapters/flat_map.rs @@ -0,0 +1,74 @@ +use core::iter::*; + +#[test] +fn test_iterator_flat_map() { + let xs = [0, 3, 6]; + let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3)); + let mut i = 0; + for x in it { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +/// Tests `FlatMap::fold` with items already picked off the front and back, +/// to make sure all parts of the `FlatMap` are folded correctly. +#[test] +fn test_iterator_flat_map_fold() { + let xs = [0, 3, 6]; + let ys = [1, 2, 3, 4, 5, 6, 7]; + let mut it = xs.iter().flat_map(|&x| x..x + 3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.fold(0, |i, x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let mut it = xs.iter().flat_map(|&x| x..x + 3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.rfold(ys.len(), |i, x| { + assert_eq!(x, ys[i - 1]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_flat_map_try_folds() { + let f = &|acc, x| i32::checked_add(acc * 2 / 3, x); + let mr = &|x| (5 * x)..(5 * x + 5); + assert_eq!((0..10).flat_map(mr).try_fold(7, f), (0..50).try_fold(7, f)); + assert_eq!((0..10).flat_map(mr).try_rfold(7, f), (0..50).try_rfold(7, f)); + let mut iter = (0..10).flat_map(mr); + iter.next(); + iter.next_back(); // have front and back iters in progress + assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f)); + + let mut iter = (0..10).flat_map(|x| (4 * x)..(4 * x + 4)); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(17)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(35)); +} + +#[test] +fn test_double_ended_flat_map() { + let u = [0, 1]; + let v = [5, 6, 7, 8]; + let mut it = u.iter().flat_map(|x| &v[*x..v.len()]); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &5); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next_back(), None); +} diff --git a/library/coretests/tests/iter/adapters/flatten.rs b/library/coretests/tests/iter/adapters/flatten.rs new file mode 100644 index 00000000000..66b7b6cb563 --- /dev/null +++ b/library/coretests/tests/iter/adapters/flatten.rs @@ -0,0 +1,281 @@ +use core::assert_eq; +use core::iter::*; +use core::num::NonZero; + +use super::*; + +#[test] +fn test_iterator_flatten() { + let xs = [0, 3, 6]; + let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten(); + let mut i = 0; + for x in it { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +/// Tests `Flatten::fold` with items already picked off the front and back, +/// to make sure all parts of the `Flatten` are folded correctly. +#[test] +fn test_iterator_flatten_fold() { + let xs = [0, 3, 6]; + let ys = [1, 2, 3, 4, 5, 6, 7]; + let mut it = xs.iter().map(|&x| x..x + 3).flatten(); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.fold(0, |i, x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let mut it = xs.iter().map(|&x| x..x + 3).flatten(); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next_back(), Some(8)); + let i = it.rfold(ys.len(), |i, x| { + assert_eq!(x, ys[i - 1]); + i - 1 + }); + assert_eq!(i, 0); +} + +#[test] +fn test_flatten_try_folds() { + let f = &|acc, x| i32::checked_add(acc * 2 / 3, x); + let mr = &|x| (5 * x)..(5 * x + 5); + assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f)); + assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f)); + let mut iter = (0..10).map(mr).flatten(); + iter.next(); + iter.next_back(); // have front and back iters in progress + assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f)); + + let mut iter = (0..10).map(|x| (4 * x)..(4 * x + 4)).flatten(); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(17)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(35)); +} + +#[test] +fn test_flatten_advance_by() { + let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); + + assert_eq!(it.advance_by(5), Ok(())); + assert_eq!(it.next(), Some(5)); + assert_eq!(it.advance_by(9), Ok(())); + assert_eq!(it.next(), Some(15)); + assert_eq!(it.advance_back_by(4), Ok(())); + assert_eq!(it.next_back(), Some(35)); + assert_eq!(it.advance_back_by(9), Ok(())); + assert_eq!(it.next_back(), Some(25)); + + assert_eq!(it.advance_by(usize::MAX), Err(NonZero::new(usize::MAX - 9).unwrap())); + assert_eq!(it.advance_back_by(usize::MAX), Err(NonZero::new(usize::MAX).unwrap())); + assert_eq!(it.advance_by(0), Ok(())); + assert_eq!(it.advance_back_by(0), Ok(())); + assert_eq!(it.size_hint(), (0, Some(0))); +} + +#[test] +fn test_flatten_non_fused_outer() { + let mut iter = NonFused::new(once(0..2)).flatten(); + + assert_eq!(iter.next_back(), Some(1)); + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut iter = NonFused::new(once(0..2)).flatten(); + + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.next_back(), Some(1)); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); +} + +#[test] +fn test_flatten_non_fused_inner() { + let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new); + + assert_eq!(iter.next_back(), Some(2)); + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new); + + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.next_back(), Some(2)); + assert_eq!(iter.next_back(), Some(1)); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); +} + +#[test] +fn test_double_ended_flatten() { + let u = [0, 1]; + let v = [5, 6, 7, 8]; + let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten(); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &5); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &8); + assert_eq!(it.next().unwrap(), &6); + assert_eq!(it.next_back().unwrap(), &7); + assert_eq!(it.next_back(), None); + assert_eq!(it.next(), None); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_trusted_len_flatten() { + fn assert_trusted_len(_: &T) {} + let mut iter = IntoIterator::into_iter([[0; 3]; 4]).flatten(); + assert_trusted_len(&iter); + + assert_eq!(iter.size_hint(), (12, Some(12))); + iter.next(); + assert_eq!(iter.size_hint(), (11, Some(11))); + iter.next_back(); + assert_eq!(iter.size_hint(), (10, Some(10))); + + let iter = IntoIterator::into_iter([[(); usize::MAX]; 1]).flatten(); + assert_eq!(iter.size_hint(), (usize::MAX, Some(usize::MAX))); + + let iter = IntoIterator::into_iter([[(); usize::MAX]; 2]).flatten(); + assert_eq!(iter.size_hint(), (usize::MAX, None)); + + let mut a = [(); 10]; + let mut b = [(); 10]; + + let iter = IntoIterator::into_iter([&mut a, &mut b]).flatten(); + assert_trusted_len(&iter); + assert_eq!(iter.size_hint(), (20, Some(20))); + core::mem::drop(iter); + + let iter = IntoIterator::into_iter([&a, &b]).flatten(); + assert_trusted_len(&iter); + assert_eq!(iter.size_hint(), (20, Some(20))); + + let iter = [(), (), ()].iter().flat_map(|_| [(); 1000]); + assert_trusted_len(&iter); + assert_eq!(iter.size_hint(), (3000, Some(3000))); + + let iter = [(), ()].iter().flat_map(|_| &a); + assert_trusted_len(&iter); + assert_eq!(iter.size_hint(), (20, Some(20))); +} + +#[test] +fn test_flatten_count() { + let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); + + assert_eq!(it.clone().count(), 40); + assert_eq!(it.advance_by(5), Ok(())); + assert_eq!(it.clone().count(), 35); + assert_eq!(it.advance_back_by(5), Ok(())); + assert_eq!(it.clone().count(), 30); + assert_eq!(it.advance_by(10), Ok(())); + assert_eq!(it.clone().count(), 20); + assert_eq!(it.advance_back_by(8), Ok(())); + assert_eq!(it.clone().count(), 12); + assert_eq!(it.advance_by(4), Ok(())); + assert_eq!(it.clone().count(), 8); + assert_eq!(it.advance_back_by(5), Ok(())); + assert_eq!(it.clone().count(), 3); + assert_eq!(it.advance_by(3), Ok(())); + assert_eq!(it.clone().count(), 0); +} + +#[test] +fn test_flatten_last() { + let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); + + assert_eq!(it.clone().last(), Some(39)); + assert_eq!(it.advance_by(5), Ok(())); // 5..40 + assert_eq!(it.clone().last(), Some(39)); + assert_eq!(it.advance_back_by(5), Ok(())); // 5..35 + assert_eq!(it.clone().last(), Some(34)); + assert_eq!(it.advance_by(10), Ok(())); // 15..35 + assert_eq!(it.clone().last(), Some(34)); + assert_eq!(it.advance_back_by(8), Ok(())); // 15..27 + assert_eq!(it.clone().last(), Some(26)); + assert_eq!(it.advance_by(4), Ok(())); // 19..27 + assert_eq!(it.clone().last(), Some(26)); + assert_eq!(it.advance_back_by(5), Ok(())); // 19..22 + assert_eq!(it.clone().last(), Some(21)); + assert_eq!(it.advance_by(3), Ok(())); // 22..22 + assert_eq!(it.clone().last(), None); +} + +#[test] +fn test_flatten_one_shot() { + // This could be `filter_map`, but people often do flatten options. + let mut it = (0i8..10).flat_map(|i| NonZero::new(i % 7)); + assert_eq!(it.size_hint(), (0, Some(10))); + assert_eq!(it.clone().count(), 8); + assert_eq!(it.clone().last(), NonZero::new(2)); + + // sum -> fold + let sum: i8 = it.clone().map(|n| n.get()).sum(); + assert_eq!(sum, 24); + + // the product overflows at 6, remaining are 7,8,9 -> 1,2 + let one = NonZero::new(1i8).unwrap(); + let product = it.try_fold(one, |acc, x| acc.checked_mul(x)); + assert_eq!(product, None); + assert_eq!(it.size_hint(), (0, Some(3))); + assert_eq!(it.clone().count(), 2); + + assert_eq!(it.advance_by(0), Ok(())); + assert_eq!(it.clone().next(), NonZero::new(1)); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.clone().next(), NonZero::new(2)); + assert_eq!(it.advance_by(100), Err(NonZero::new(99).unwrap())); + assert_eq!(it.next(), None); +} + +#[test] +fn test_flatten_one_shot_rev() { + let mut it = (0i8..10).flat_map(|i| NonZero::new(i % 7)).rev(); + assert_eq!(it.size_hint(), (0, Some(10))); + assert_eq!(it.clone().count(), 8); + assert_eq!(it.clone().last(), NonZero::new(1)); + + // sum -> Rev fold -> rfold + let sum: i8 = it.clone().map(|n| n.get()).sum(); + assert_eq!(sum, 24); + + // Rev try_fold -> try_rfold + // the product overflows at 4, remaining are 3,2,1,0 -> 3,2,1 + let one = NonZero::new(1i8).unwrap(); + let product = it.try_fold(one, |acc, x| acc.checked_mul(x)); + assert_eq!(product, None); + assert_eq!(it.size_hint(), (0, Some(4))); + assert_eq!(it.clone().count(), 3); + + // Rev advance_by -> advance_back_by + assert_eq!(it.advance_by(0), Ok(())); + assert_eq!(it.clone().next(), NonZero::new(3)); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.clone().next(), NonZero::new(2)); + assert_eq!(it.advance_by(100), Err(NonZero::new(98).unwrap())); + assert_eq!(it.next(), None); +} + +#[test] +fn test_flatten_one_shot_arrays() { + let it = (0..10).flat_map(|i| [i]); + assert_eq!(it.size_hint(), (10, Some(10))); + assert_eq!(it.sum::(), 45); + + let mut it = (0..10).flat_map(|_| -> [i32; 0] { [] }); + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None); +} diff --git a/library/coretests/tests/iter/adapters/fuse.rs b/library/coretests/tests/iter/adapters/fuse.rs new file mode 100644 index 00000000000..f41b379b3ac --- /dev/null +++ b/library/coretests/tests/iter/adapters/fuse.rs @@ -0,0 +1,75 @@ +use core::iter::*; + +#[test] +fn test_fuse_nth() { + let xs = [0, 1, 2]; + let mut it = xs.iter(); + + assert_eq!(it.len(), 3); + assert_eq!(it.nth(2), Some(&2)); + assert_eq!(it.len(), 0); + assert_eq!(it.nth(2), None); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_fuse_last() { + let xs = [0, 1, 2]; + let it = xs.iter(); + + assert_eq!(it.len(), 3); + assert_eq!(it.last(), Some(&2)); +} + +#[test] +fn test_fuse_count() { + let xs = [0, 1, 2]; + let it = xs.iter(); + + assert_eq!(it.len(), 3); + assert_eq!(it.count(), 3); + // Can't check len now because count consumes. +} + +#[test] +fn test_fuse_fold() { + let xs = [0, 1, 2]; + let it = xs.iter(); // `FusedIterator` + let i = it.fuse().fold(0, |i, &x| { + assert_eq!(x, xs[i]); + i + 1 + }); + assert_eq!(i, xs.len()); + + let it = xs.iter(); // `FusedIterator` + let i = it.fuse().rfold(xs.len(), |i, &x| { + assert_eq!(x, xs[i - 1]); + i - 1 + }); + assert_eq!(i, 0); + + let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator` + let i = it.fuse().fold(0, |i, x| { + assert_eq!(x, xs[i]); + i + 1 + }); + assert_eq!(i, xs.len()); +} + +#[test] +fn test_fuse() { + let mut it = 0..3; + assert_eq!(it.len(), 3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.len(), 2); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.len(), 1); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.len(), 0); + assert_eq!(it.next(), None); + assert_eq!(it.len(), 0); + assert_eq!(it.next(), None); + assert_eq!(it.len(), 0); + assert_eq!(it.next(), None); + assert_eq!(it.len(), 0); +} diff --git a/library/coretests/tests/iter/adapters/inspect.rs b/library/coretests/tests/iter/adapters/inspect.rs new file mode 100644 index 00000000000..939e3a28a72 --- /dev/null +++ b/library/coretests/tests/iter/adapters/inspect.rs @@ -0,0 +1,38 @@ +use core::iter::*; + +#[test] +fn test_inspect() { + let xs = [1, 2, 3, 4]; + let mut n = 0; + + let ys = xs.iter().cloned().inspect(|_| n += 1).collect::>(); + + assert_eq!(n, xs.len()); + assert_eq!(&xs[..], &ys[..]); +} + +#[test] +fn test_inspect_fold() { + let xs = [1, 2, 3, 4]; + let mut n = 0; + { + let it = xs.iter().inspect(|_| n += 1); + let i = it.fold(0, |i, &x| { + assert_eq!(x, xs[i]); + i + 1 + }); + assert_eq!(i, xs.len()); + } + assert_eq!(n, xs.len()); + + let mut n = 0; + { + let it = xs.iter().inspect(|_| n += 1); + let i = it.rfold(xs.len(), |i, &x| { + assert_eq!(x, xs[i - 1]); + i - 1 + }); + assert_eq!(i, 0); + } + assert_eq!(n, xs.len()); +} diff --git a/library/coretests/tests/iter/adapters/intersperse.rs b/library/coretests/tests/iter/adapters/intersperse.rs new file mode 100644 index 00000000000..72ae59b6b2f --- /dev/null +++ b/library/coretests/tests/iter/adapters/intersperse.rs @@ -0,0 +1,154 @@ +use core::iter::*; + +#[test] +fn test_intersperse() { + let v = std::iter::empty().intersperse(0u32).collect::>(); + assert_eq!(v, vec![]); + + let v = std::iter::once(1).intersperse(0).collect::>(); + assert_eq!(v, vec![1]); + + let xs = ["a", "", "b", "c"]; + let v: Vec<&str> = xs.iter().map(|x| *x).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 test_intersperse_size_hint() { + let iter = std::iter::empty::().intersperse(0); + assert_eq!(iter.size_hint(), (0, Some(0))); + + let xs = ["a", "", "b", "c"]; + let mut iter = xs.iter().map(|x| *x).intersperse(", "); + assert_eq!(iter.size_hint(), (7, Some(7))); + + assert_eq!(iter.next(), Some("a")); + assert_eq!(iter.size_hint(), (6, Some(6))); + assert_eq!(iter.next(), Some(", ")); + assert_eq!(iter.size_hint(), (5, Some(5))); + + assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0))); +} + +#[test] +fn test_fold_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())); +} + +#[test] +fn test_try_fold_specialization_intersperse_ok() { + let mut iter = (1..2).intersperse(0); + iter.clone().try_for_each(|x| { + assert_eq!(Some(x), iter.next()); + Some(()) + }); + + let mut iter = (1..3).intersperse(0); + iter.clone().try_for_each(|x| { + assert_eq!(Some(x), iter.next()); + Some(()) + }); + + let mut iter = (1..4).intersperse(0); + iter.clone().try_for_each(|x| { + assert_eq!(Some(x), iter.next()); + Some(()) + }); +} + +#[test] +fn test_intersperse_with() { + #[derive(PartialEq, Debug)] + struct NotClone { + u: u32, + } + let r = [NotClone { u: 0 }, NotClone { u: 1 }] + .into_iter() + .intersperse_with(|| NotClone { u: 2 }) + .collect::>(); + assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]); + + let mut ctr = 100; + let separator = || { + ctr *= 2; + ctr + }; + let r = (0..3).intersperse_with(separator).collect::>(); + assert_eq!(r, vec![0, 200, 1, 400, 2]); +} + +#[test] +fn test_intersperse_fold() { + let v = (1..4).intersperse(9).fold(Vec::new(), |mut acc, x| { + acc.push(x); + acc + }); + assert_eq!(v.as_slice(), [1, 9, 2, 9, 3]); + + let mut iter = (1..4).intersperse(9); + assert_eq!(iter.next(), Some(1)); + let v = iter.fold(Vec::new(), |mut acc, x| { + acc.push(x); + acc + }); + assert_eq!(v.as_slice(), [9, 2, 9, 3]); + + struct NoneAtStart(i32); // Produces: None, Some(2), Some(3), None, ... + impl Iterator for NoneAtStart { + type Item = i32; + fn next(&mut self) -> Option { + self.0 += 1; + Some(self.0).filter(|i| i % 3 != 1) + } + } + + let v = NoneAtStart(0).intersperse(1000).fold(0, |a, b| a + b); + assert_eq!(v, 0); +} + +#[test] +fn test_intersperse_collect_string() { + let contents = [1, 2, 3]; + + let contents_string = contents + .into_iter() + .map(|id| id.to_string()) + .intersperse(", ".to_owned()) + .collect::(); + assert_eq!(contents_string, "1, 2, 3"); +} + +#[test] +fn test_try_fold_specialization_intersperse_err() { + let orig_iter = ["a", "b"].iter().copied().intersperse("-"); + + // Abort after the first item. + let mut iter = orig_iter.clone(); + iter.try_for_each(|_| None::<()>); + assert_eq!(iter.next(), Some("-")); + assert_eq!(iter.next(), Some("b")); + assert_eq!(iter.next(), None); + + // Abort after the second item. + let mut iter = orig_iter.clone(); + iter.try_for_each(|item| if item == "-" { None } else { Some(()) }); + assert_eq!(iter.next(), Some("b")); + assert_eq!(iter.next(), None); + + // Abort after the third item. + let mut iter = orig_iter.clone(); + iter.try_for_each(|item| if item == "b" { None } else { Some(()) }); + assert_eq!(iter.next(), None); +} diff --git a/library/coretests/tests/iter/adapters/map.rs b/library/coretests/tests/iter/adapters/map.rs new file mode 100644 index 00000000000..77ce3819b32 --- /dev/null +++ b/library/coretests/tests/iter/adapters/map.rs @@ -0,0 +1,27 @@ +use core::iter::*; + +#[test] +fn test_map_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((0..10).map(|x| x + 3).try_fold(7, f), (3..13).try_fold(7, f)); + assert_eq!((0..10).map(|x| x + 3).try_rfold(7, f), (3..13).try_rfold(7, f)); + + let mut iter = (0..40).map(|x| x + 10); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(20)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(46)); +} + +#[test] +fn test_double_ended_map() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut it = xs.iter().map(|&x| x * -1); + assert_eq!(it.next(), Some(-1)); + assert_eq!(it.next(), Some(-2)); + assert_eq!(it.next_back(), Some(-6)); + assert_eq!(it.next_back(), Some(-5)); + assert_eq!(it.next(), Some(-3)); + assert_eq!(it.next_back(), Some(-4)); + assert_eq!(it.next(), None); +} diff --git a/library/coretests/tests/iter/adapters/map_windows.rs b/library/coretests/tests/iter/adapters/map_windows.rs new file mode 100644 index 00000000000..b677f1cfd55 --- /dev/null +++ b/library/coretests/tests/iter/adapters/map_windows.rs @@ -0,0 +1,287 @@ +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; + +#[cfg(not(panic = "abort"))] +mod drop_checks { + //! These tests mainly make sure the elements are correctly dropped. + + use std::sync::atomic::Ordering::SeqCst; + use std::sync::atomic::{AtomicBool, AtomicUsize}; + + #[derive(Debug)] + struct DropInfo { + dropped_twice: AtomicBool, + alive_count: AtomicUsize, + } + + impl DropInfo { + const fn new() -> Self { + Self { dropped_twice: AtomicBool::new(false), alive_count: AtomicUsize::new(0) } + } + + #[track_caller] + fn check(&self) { + assert!(!self.dropped_twice.load(SeqCst), "a value was dropped twice"); + assert_eq!(self.alive_count.load(SeqCst), 0); + } + } + + #[derive(Debug)] + struct DropCheck<'a> { + info: &'a DropInfo, + was_dropped: bool, + } + + impl<'a> DropCheck<'a> { + fn new(info: &'a DropInfo) -> Self { + info.alive_count.fetch_add(1, SeqCst); + + Self { info, was_dropped: false } + } + } + + impl Drop for DropCheck<'_> { + fn drop(&mut self) { + if self.was_dropped { + self.info.dropped_twice.store(true, SeqCst); + } + self.was_dropped = true; + + self.info.alive_count.fetch_sub(1, SeqCst); + } + } + + fn iter(info: &DropInfo, len: usize, panic_at: usize) -> impl Iterator> { + (0..len).map(move |i| { + if i == panic_at { + panic!("intended panic"); + } + DropCheck::new(info) + }) + } + + #[track_caller] + fn check(len: usize, panic_at: usize) { + check_drops(|info| { + iter(info, len, panic_at).map_windows(|_: &[_; N]| {}).last(); + }); + } + + #[track_caller] + fn check_drops(f: impl FnOnce(&DropInfo)) { + let info = DropInfo::new(); + let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + f(&info); + })); + info.check(); + } + + #[test] + fn no_iter_panic_n1() { + check::<1>(0, 100); + check::<1>(1, 100); + check::<1>(2, 100); + check::<1>(13, 100); + } + + #[test] + fn no_iter_panic_n2() { + check::<2>(0, 100); + check::<2>(1, 100); + check::<2>(2, 100); + check::<2>(3, 100); + check::<2>(13, 100); + } + + #[test] + fn no_iter_panic_n5() { + check::<5>(0, 100); + check::<5>(1, 100); + check::<5>(2, 100); + check::<5>(13, 100); + check::<5>(30, 100); + } + + #[test] + fn panic_in_first_batch() { + check::<1>(7, 0); + + check::<2>(7, 0); + check::<2>(7, 1); + + check::<3>(7, 0); + check::<3>(7, 1); + check::<3>(7, 2); + } + + #[test] + fn panic_in_middle() { + check::<1>(7, 1); + check::<1>(7, 5); + check::<1>(7, 6); + + check::<2>(7, 2); + check::<2>(7, 5); + check::<2>(7, 6); + + check::<5>(13, 5); + check::<5>(13, 8); + check::<5>(13, 12); + } + + #[test] + fn len_equals_n() { + check::<1>(1, 100); + check::<1>(1, 0); + + check::<2>(2, 100); + check::<2>(2, 0); + check::<2>(2, 1); + + check::<5>(5, 100); + check::<5>(5, 0); + check::<5>(5, 1); + check::<5>(5, 4); + } +} + +#[test] +fn output_n1() { + assert_eq!("".chars().map_windows(|[c]| *c).collect::>(), vec![]); + assert_eq!("x".chars().map_windows(|[c]| *c).collect::>(), vec!['x']); + assert_eq!("abcd".chars().map_windows(|[c]| *c).collect::>(), vec!['a', 'b', 'c', 'd']); +} + +#[test] +fn output_n2() { + assert_eq!( + "".chars().map_windows(|a: &[_; 2]| *a).collect::>(), + >::new(), + ); + assert_eq!("ab".chars().map_windows(|a: &[_; 2]| *a).collect::>(), vec![['a', 'b']]); + assert_eq!("abcd".chars().map_windows(|a: &[_; 2]| *a).collect::>(), vec![ + ['a', 'b'], + ['b', 'c'], + ['c', 'd'] + ],); +} + +#[test] +fn test_case_from_pr_82413_comment() { + for () in std::iter::repeat("0".to_owned()).map_windows(|_: &[_; 3]| {}).take(4) {} +} + +#[test] +#[should_panic = "array in `Iterator::map_windows` must contain more than 0 elements"] +fn check_zero_window() { + let _ = std::iter::repeat(0).map_windows(|_: &[_; 0]| ()); +} + +#[test] +fn test_zero_sized_type() { + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + struct Data; + let data: Vec<_> = + std::iter::repeat(Data).take(10).map_windows(|arr: &[Data; 5]| *arr).collect(); + assert_eq!(data, [[Data; 5]; 6]); +} + +#[test] +#[should_panic = "array size of `Iterator::map_windows` is too large"] +fn test_too_large_array_size() { + let _ = std::iter::repeat(()).map_windows(|arr: &[(); usize::MAX]| *arr); +} + +#[test] +fn test_laziness() { + let counter = AtomicUsize::new(0); + let mut iter = (0..5) + .inspect(|_| { + counter.fetch_add(1, SeqCst); + }) + .map_windows(|arr: &[i32; 2]| *arr); + assert_eq!(counter.load(SeqCst), 0); + + assert_eq!(iter.next(), Some([0, 1])); + // The first iteration consumes N items (N = 2). + assert_eq!(counter.load(SeqCst), 2); + + assert_eq!(iter.next(), Some([1, 2])); + assert_eq!(counter.load(SeqCst), 3); + + assert_eq!(iter.next(), Some([2, 3])); + assert_eq!(counter.load(SeqCst), 4); + + assert_eq!(iter.next(), Some([3, 4])); + assert_eq!(counter.load(SeqCst), 5); + + assert_eq!(iter.next(), None); + assert_eq!(counter.load(SeqCst), 5); +} + +#[test] +fn test_size_hint() { + struct SizeHintCheckHelper((usize, Option)); + + impl Iterator for SizeHintCheckHelper { + type Item = i32; + + fn next(&mut self) -> Option { + let (ref mut lo, ref mut hi) = self.0; + let next = (*hi != Some(0)).then_some(0); + *lo = lo.saturating_sub(1); + if let Some(hi) = hi { + *hi = hi.saturating_sub(1); + } + next + } + + fn size_hint(&self) -> (usize, Option) { + self.0 + } + } + + fn check_size_hint( + size_hint: (usize, Option), + mut mapped_size_hint: (usize, Option), + ) { + let mut iter = SizeHintCheckHelper(size_hint); + let mut mapped_iter = iter.by_ref().map_windows(|_: &[_; N]| ()); + while mapped_iter.size_hint().0 > 0 { + assert_eq!(mapped_iter.size_hint(), mapped_size_hint); + assert!(mapped_iter.next().is_some()); + mapped_size_hint.0 -= 1; + mapped_size_hint.1 = mapped_size_hint.1.map(|hi| hi.saturating_sub(1)); + } + } + + check_size_hint::<1>((0, None), (0, None)); + check_size_hint::<1>((0, Some(0)), (0, Some(0))); + check_size_hint::<1>((0, Some(2)), (0, Some(2))); + check_size_hint::<1>((1, None), (1, None)); + check_size_hint::<1>((1, Some(1)), (1, Some(1))); + check_size_hint::<1>((1, Some(4)), (1, Some(4))); + check_size_hint::<1>((5, None), (5, None)); + check_size_hint::<1>((5, Some(5)), (5, Some(5))); + check_size_hint::<1>((5, Some(10)), (5, Some(10))); + + check_size_hint::<2>((0, None), (0, None)); + check_size_hint::<2>((0, Some(0)), (0, Some(0))); + check_size_hint::<2>((0, Some(2)), (0, Some(1))); + check_size_hint::<2>((1, None), (0, None)); + check_size_hint::<2>((1, Some(1)), (0, Some(0))); + check_size_hint::<2>((1, Some(4)), (0, Some(3))); + check_size_hint::<2>((5, None), (4, None)); + check_size_hint::<2>((5, Some(5)), (4, Some(4))); + check_size_hint::<2>((5, Some(10)), (4, Some(9))); + + check_size_hint::<5>((0, None), (0, None)); + check_size_hint::<5>((0, Some(0)), (0, Some(0))); + check_size_hint::<5>((0, Some(2)), (0, Some(0))); + check_size_hint::<5>((1, None), (0, None)); + check_size_hint::<5>((1, Some(1)), (0, Some(0))); + check_size_hint::<5>((1, Some(4)), (0, Some(0))); + check_size_hint::<5>((5, None), (1, None)); + check_size_hint::<5>((5, Some(5)), (1, Some(1))); + check_size_hint::<5>((5, Some(10)), (1, Some(6))); +} diff --git a/library/coretests/tests/iter/adapters/mod.rs b/library/coretests/tests/iter/adapters/mod.rs new file mode 100644 index 00000000000..dedb4c0a9dd --- /dev/null +++ b/library/coretests/tests/iter/adapters/mod.rs @@ -0,0 +1,210 @@ +mod array_chunks; +mod by_ref_sized; +mod chain; +mod cloned; +mod copied; +mod cycle; +mod enumerate; +mod filter; +mod filter_map; +mod flat_map; +mod flatten; +mod fuse; +mod inspect; +mod intersperse; +mod map; +mod map_windows; +mod peekable; +mod scan; +mod skip; +mod skip_while; +mod step_by; +mod take; +mod take_while; +mod zip; + +use core::cell::Cell; + +/// An iterator that panics whenever `next` or `next_back` is called +/// after `None` has already been returned. This does not violate +/// `Iterator`'s contract. Used to test that iterator adapters don't +/// poll their inner iterators after exhausting them. +pub struct NonFused { + iter: I, + done: bool, +} + +impl NonFused { + pub fn new(iter: I) -> Self { + Self { iter, done: false } + } +} + +impl Iterator for NonFused +where + I: Iterator, +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + assert!(!self.done, "this iterator has already returned None"); + self.iter.next().or_else(|| { + self.done = true; + None + }) + } +} + +impl DoubleEndedIterator for NonFused +where + I: DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option { + assert!(!self.done, "this iterator has already returned None"); + self.iter.next_back().or_else(|| { + self.done = true; + None + }) + } +} + +/// An iterator wrapper that panics whenever `next` or `next_back` is called +/// after `None` has been returned. +pub struct Unfuse { + iter: I, + exhausted: bool, +} + +impl Unfuse { + pub fn new(iter: T) -> Self + where + T: IntoIterator, + { + Self { iter: iter.into_iter(), exhausted: false } + } +} + +impl Iterator for Unfuse +where + I: Iterator, +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + assert!(!self.exhausted); + let next = self.iter.next(); + self.exhausted = next.is_none(); + next + } +} + +impl DoubleEndedIterator for Unfuse +where + I: DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option { + assert!(!self.exhausted); + let next = self.iter.next_back(); + self.exhausted = next.is_none(); + next + } +} + +pub struct Toggle { + is_empty: bool, +} + +impl Iterator for Toggle { + type Item = (); + + // alternates between `None` and `Some(())` + fn next(&mut self) -> Option { + if self.is_empty { + self.is_empty = false; + None + } else { + self.is_empty = true; + Some(()) + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.is_empty { (0, Some(0)) } else { (1, Some(1)) } + } +} + +impl DoubleEndedIterator for Toggle { + fn next_back(&mut self) -> Option { + self.next() + } +} + +/// This is an iterator that follows the Iterator contract, +/// but it is not fused. After having returned None once, it will start +/// producing elements if .next() is called again. +pub struct CycleIter<'a, T> { + index: usize, + data: &'a [T], +} + +impl<'a, T> CycleIter<'a, T> { + pub fn new(data: &'a [T]) -> Self { + Self { index: 0, data } + } +} + +impl<'a, T> Iterator for CycleIter<'a, T> { + type Item = &'a T; + fn next(&mut self) -> Option { + let elt = self.data.get(self.index); + self.index += 1; + self.index %= 1 + self.data.len(); + elt + } +} + +#[derive(Debug)] +struct CountClone(Cell); + +impl CountClone { + pub fn new() -> Self { + Self(Cell::new(0)) + } +} + +impl PartialEq for CountClone { + fn eq(&self, rhs: &i32) -> bool { + self.0.get() == *rhs + } +} + +impl Clone for CountClone { + fn clone(&self) -> Self { + let ret = CountClone(self.0.clone()); + let n = self.0.get(); + self.0.set(n + 1); + ret + } +} + +#[derive(Debug, Clone)] +struct CountDrop<'a> { + dropped: bool, + count: &'a Cell, +} + +impl<'a> CountDrop<'a> { + pub fn new(count: &'a Cell) -> Self { + Self { dropped: false, count } + } +} + +impl Drop for CountDrop<'_> { + fn drop(&mut self) { + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + self.count.set(self.count.get() + 1); + } +} diff --git a/library/coretests/tests/iter/adapters/peekable.rs b/library/coretests/tests/iter/adapters/peekable.rs new file mode 100644 index 00000000000..7f4341b8902 --- /dev/null +++ b/library/coretests/tests/iter/adapters/peekable.rs @@ -0,0 +1,273 @@ +use core::iter::*; + +use super::*; + +#[test] +fn test_iterator_peekable() { + let xs = vec![0, 1, 2, 3, 4, 5]; + + let mut it = xs.iter().cloned().peekable(); + assert_eq!(it.len(), 6); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 6); + assert_eq!(it.next().unwrap(), 0); + assert_eq!(it.len(), 5); + assert_eq!(it.next().unwrap(), 1); + assert_eq!(it.len(), 4); + assert_eq!(it.next().unwrap(), 2); + assert_eq!(it.len(), 3); + assert_eq!(it.peek().unwrap(), &3); + assert_eq!(it.len(), 3); + assert_eq!(it.peek().unwrap(), &3); + assert_eq!(it.len(), 3); + assert_eq!(it.next().unwrap(), 3); + assert_eq!(it.len(), 2); + assert_eq!(it.next().unwrap(), 4); + assert_eq!(it.len(), 1); + assert_eq!(it.peek().unwrap(), &5); + assert_eq!(it.len(), 1); + assert_eq!(it.next().unwrap(), 5); + assert_eq!(it.len(), 0); + assert!(it.peek().is_none()); + assert_eq!(it.len(), 0); + assert!(it.next().is_none()); + assert_eq!(it.len(), 0); + + let mut it = xs.iter().cloned().peekable(); + assert_eq!(it.len(), 6); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 6); + assert_eq!(it.next_back().unwrap(), 5); + assert_eq!(it.len(), 5); + assert_eq!(it.next_back().unwrap(), 4); + assert_eq!(it.len(), 4); + assert_eq!(it.next_back().unwrap(), 3); + assert_eq!(it.len(), 3); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 3); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 3); + assert_eq!(it.next_back().unwrap(), 2); + assert_eq!(it.len(), 2); + assert_eq!(it.next_back().unwrap(), 1); + assert_eq!(it.len(), 1); + assert_eq!(it.peek().unwrap(), &0); + assert_eq!(it.len(), 1); + assert_eq!(it.next_back().unwrap(), 0); + assert_eq!(it.len(), 0); + assert!(it.peek().is_none()); + assert_eq!(it.len(), 0); + assert!(it.next_back().is_none()); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_iterator_peekable_count() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [10]; + let zs: [i32; 0] = []; + + assert_eq!(xs.iter().peekable().count(), 6); + + let mut it = xs.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + assert_eq!(it.count(), 6); + + assert_eq!(ys.iter().peekable().count(), 1); + + let mut it = ys.iter().peekable(); + assert_eq!(it.peek(), Some(&&10)); + assert_eq!(it.count(), 1); + + assert_eq!(zs.iter().peekable().count(), 0); + + let mut it = zs.iter().peekable(); + assert_eq!(it.peek(), None); +} + +#[test] +fn test_iterator_peekable_nth() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().peekable(); + + assert_eq!(it.peek(), Some(&&0)); + assert_eq!(it.nth(0), Some(&0)); + assert_eq!(it.peek(), Some(&&1)); + assert_eq!(it.nth(1), Some(&2)); + assert_eq!(it.peek(), Some(&&3)); + assert_eq!(it.nth(2), Some(&5)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_iterator_peekable_last() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [0]; + + let mut it = xs.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + assert_eq!(it.last(), Some(&5)); + + let mut it = ys.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + assert_eq!(it.last(), Some(&0)); + + let mut it = ys.iter().peekable(); + assert_eq!(it.next(), Some(&0)); + assert_eq!(it.peek(), None); + assert_eq!(it.last(), None); +} + +#[test] +fn test_iterator_peekable_fold() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + let i = it.fold(0, |i, &x| { + assert_eq!(x, xs[i]); + i + 1 + }); + assert_eq!(i, xs.len()); +} + +#[test] +fn test_iterator_peekable_rfold() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().peekable(); + assert_eq!(it.peek(), Some(&&0)); + let i = it.rfold(0, |i, &x| { + assert_eq!(x, xs[xs.len() - 1 - i]); + i + 1 + }); + assert_eq!(i, xs.len()); +} + +#[test] +fn test_iterator_peekable_next_if_eq() { + // first, try on references + let xs = ["Heart", "of", "Gold"]; + let mut it = xs.into_iter().peekable(); + // try before `peek()` + assert_eq!(it.next_if_eq(&"trillian"), None); + assert_eq!(it.next_if_eq(&"Heart"), Some("Heart")); + // try after peek() + assert_eq!(it.peek(), Some(&"of")); + assert_eq!(it.next_if_eq(&"of"), Some("of")); + assert_eq!(it.next_if_eq(&"zaphod"), None); + // make sure `next()` still behaves + assert_eq!(it.next(), Some("Gold")); + + // make sure comparison works for owned values + let xs = [String::from("Ludicrous"), "speed".into()]; + let mut it = xs.into_iter().peekable(); + // make sure basic functionality works + assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into())); + assert_eq!(it.next_if_eq("speed"), Some("speed".into())); + assert_eq!(it.next_if_eq(""), None); +} + +#[test] +fn test_iterator_peekable_mut() { + let mut it = [1, 2, 3].into_iter().peekable(); + if let Some(p) = it.peek_mut() { + if *p == 1 { + *p = 5; + } + } + assert_eq!(it.collect::>(), vec![5, 2, 3]); +} + +#[test] +fn test_iterator_peekable_remember_peek_none_1() { + // Check that the loop using .peek() terminates + let data = [1, 2, 3]; + let mut iter = CycleIter::new(&data).peekable(); + + let mut n = 0; + while let Some(_) = iter.next() { + let is_the_last = iter.peek().is_none(); + assert_eq!(is_the_last, n == data.len() - 1); + n += 1; + if n > data.len() { + break; + } + } + assert_eq!(n, data.len()); +} + +#[test] +fn test_iterator_peekable_remember_peek_none_2() { + let data = [0]; + let mut iter = CycleIter::new(&data).peekable(); + iter.next(); + assert_eq!(iter.peek(), None); + assert_eq!(iter.last(), None); +} + +#[test] +fn test_iterator_peekable_remember_peek_none_3() { + let data = [0]; + let mut iter = CycleIter::new(&data).peekable(); + iter.peek(); + assert_eq!(iter.nth(0), Some(&0)); + + let mut iter = CycleIter::new(&data).peekable(); + iter.next(); + assert_eq!(iter.peek(), None); + assert_eq!(iter.nth(0), None); +} + +#[test] +fn test_peek_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + + assert_eq!((1..20).peekable().try_fold(7, f), (1..20).try_fold(7, f)); + assert_eq!((1..20).peekable().try_rfold(7, f), (1..20).try_rfold(7, f)); + + let mut iter = (1..20).peekable(); + assert_eq!(iter.peek(), Some(&1)); + assert_eq!(iter.try_fold(7, f), (1..20).try_fold(7, f)); + + let mut iter = (1..20).peekable(); + assert_eq!(iter.peek(), Some(&1)); + assert_eq!(iter.try_rfold(7, f), (1..20).try_rfold(7, f)); + + let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable(); + assert_eq!(iter.peek(), Some(&100)); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.peek(), Some(&40)); + + let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable(); + assert_eq!(iter.peek(), Some(&100)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.peek(), Some(&100)); + assert_eq!(iter.next_back(), Some(50)); + + let mut iter = (2..5).peekable(); + assert_eq!(iter.peek(), Some(&2)); + assert_eq!(iter.try_for_each(Err), Err(2)); + assert_eq!(iter.peek(), Some(&3)); + assert_eq!(iter.try_for_each(Err), Err(3)); + assert_eq!(iter.peek(), Some(&4)); + assert_eq!(iter.try_for_each(Err), Err(4)); + assert_eq!(iter.peek(), None); + assert_eq!(iter.try_for_each(Err), Ok(())); + + let mut iter = (2..5).peekable(); + assert_eq!(iter.peek(), Some(&2)); + assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(4)); + assert_eq!(iter.peek(), Some(&2)); + assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(3)); + assert_eq!(iter.peek(), Some(&2)); + assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(2)); + assert_eq!(iter.peek(), None); + assert_eq!(iter.try_rfold((), |(), x| Err(x)), Ok(())); +} + +#[test] +fn test_peekable_non_fused() { + let mut iter = NonFused::new(empty::()).peekable(); + + assert_eq!(iter.peek(), None); + assert_eq!(iter.next_back(), None); +} diff --git a/library/coretests/tests/iter/adapters/scan.rs b/library/coretests/tests/iter/adapters/scan.rs new file mode 100644 index 00000000000..1d28ca6b7fd --- /dev/null +++ b/library/coretests/tests/iter/adapters/scan.rs @@ -0,0 +1,20 @@ +use core::iter::*; + +#[test] +fn test_iterator_scan() { + // test the type inference + fn add(old: &mut isize, new: &usize) -> Option { + *old += *new as isize; + Some(*old as f64) + } + let xs = [0, 1, 2, 3, 4]; + let ys = [0f64, 1.0, 3.0, 6.0, 10.0]; + + let it = xs.iter().scan(0, add); + let mut i = 0; + for x in it { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} diff --git a/library/coretests/tests/iter/adapters/skip.rs b/library/coretests/tests/iter/adapters/skip.rs new file mode 100644 index 00000000000..8d5d06ad9fb --- /dev/null +++ b/library/coretests/tests/iter/adapters/skip.rs @@ -0,0 +1,238 @@ +use core::iter::*; +use core::num::NonZero; + +use super::Unfuse; + +#[test] +fn test_iterator_skip() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + let ys = [13, 15, 16, 17, 19, 20, 30]; + let mut it = xs.iter().skip(5); + let mut i = 0; + while let Some(&x) = it.next() { + assert_eq!(x, ys[i]); + i += 1; + assert_eq!(it.len(), xs.len() - 5 - i); + } + assert_eq!(i, ys.len()); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_iterator_skip_doubleended() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + let mut it = xs.iter().rev().skip(5); + assert_eq!(it.next(), Some(&15)); + assert_eq!(it.by_ref().rev().next(), Some(&0)); + assert_eq!(it.next(), Some(&13)); + assert_eq!(it.by_ref().rev().next(), Some(&1)); + assert_eq!(it.next(), Some(&5)); + assert_eq!(it.by_ref().rev().next(), Some(&2)); + assert_eq!(it.next(), Some(&3)); + assert_eq!(it.next(), None); + let mut it = xs.iter().rev().skip(5).rev(); + assert_eq!(it.next(), Some(&0)); + assert_eq!(it.rev().next(), Some(&15)); + let mut it_base = xs.iter(); + { + let mut it = it_base.by_ref().skip(5).rev(); + assert_eq!(it.next(), Some(&30)); + assert_eq!(it.next(), Some(&20)); + assert_eq!(it.next(), Some(&19)); + assert_eq!(it.next(), Some(&17)); + assert_eq!(it.next(), Some(&16)); + assert_eq!(it.next(), Some(&15)); + assert_eq!(it.next(), Some(&13)); + assert_eq!(it.next(), None); + } + // make sure the skipped parts have not been consumed + assert_eq!(it_base.next(), Some(&0)); + assert_eq!(it_base.next(), Some(&1)); + assert_eq!(it_base.next(), Some(&2)); + assert_eq!(it_base.next(), Some(&3)); + assert_eq!(it_base.next(), Some(&5)); + assert_eq!(it_base.next(), None); + let it = xs.iter().skip(5).rev(); + assert_eq!(it.last(), Some(&13)); +} + +#[test] +fn test_iterator_skip_nth() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + + let mut it = xs.iter().skip(0); + assert_eq!(it.nth(0), Some(&0)); + assert_eq!(it.nth(1), Some(&2)); + + let mut it = xs.iter().skip(5); + assert_eq!(it.nth(0), Some(&13)); + assert_eq!(it.nth(1), Some(&16)); + + let mut it = xs.iter().skip(12); + assert_eq!(it.nth(0), None); +} + +#[test] +fn test_skip_advance_by() { + assert_eq!((0..0).skip(10).advance_by(0), Ok(())); + assert_eq!((0..0).skip(10).advance_by(1), Err(NonZero::new(1).unwrap())); + assert_eq!( + (0u128..(usize::MAX as u128) + 1).skip(usize::MAX - 10).advance_by(usize::MAX - 5), + Err(NonZero::new(usize::MAX - 16).unwrap()) + ); + assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), Ok(())); + + assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZero::new(9).unwrap())); + assert_eq!((0..0).skip(1).advance_back_by(0), Ok(())); +} + +#[test] +fn test_iterator_skip_count() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + + assert_eq!(xs.iter().skip(0).count(), 12); + assert_eq!(xs.iter().skip(1).count(), 11); + assert_eq!(xs.iter().skip(11).count(), 1); + assert_eq!(xs.iter().skip(12).count(), 0); + assert_eq!(xs.iter().skip(13).count(), 0); +} + +#[test] +fn test_iterator_skip_last() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + + assert_eq!(xs.iter().skip(0).last(), Some(&30)); + assert_eq!(xs.iter().skip(1).last(), Some(&30)); + assert_eq!(xs.iter().skip(11).last(), Some(&30)); + assert_eq!(xs.iter().skip(12).last(), None); + assert_eq!(xs.iter().skip(13).last(), None); + + let mut it = xs.iter().skip(5); + assert_eq!(it.next(), Some(&13)); + assert_eq!(it.last(), Some(&30)); +} + +#[test] +fn test_iterator_skip_fold() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; + let ys = [13, 15, 16, 17, 19, 20, 30]; + + let it = xs.iter().skip(5); + let i = it.fold(0, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let mut it = xs.iter().skip(5); + assert_eq!(it.next(), Some(&ys[0])); // process skips before folding + let i = it.fold(1, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let it = xs.iter().skip(5); + let i = it.rfold(ys.len(), |i, &x| { + let i = i - 1; + assert_eq!(x, ys[i]); + i + }); + assert_eq!(i, 0); + + let mut it = xs.iter().skip(5); + assert_eq!(it.next(), Some(&ys[0])); // process skips before folding + let i = it.rfold(ys.len(), |i, &x| { + let i = i - 1; + assert_eq!(x, ys[i]); + i + }); + assert_eq!(i, 1); +} + +#[test] +fn test_skip_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((1..20).skip(9).try_fold(7, f), (10..20).try_fold(7, f)); + assert_eq!((1..20).skip(9).try_rfold(7, f), (10..20).try_rfold(7, f)); + + let mut iter = (0..30).skip(10); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(20)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(24)); +} + +#[test] +fn test_skip_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().skip(2); + assert_eq!(it.nth_back(0), Some(&5)); + assert_eq!(it.nth_back(1), Some(&3)); + assert_eq!(it.nth_back(0), Some(&2)); + assert_eq!(it.nth_back(0), None); + + let ys = [2, 3, 4, 5]; + let mut ity = ys.iter(); + let mut it = xs.iter().skip(2); + assert_eq!(it.nth_back(1), ity.nth_back(1)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + assert_eq!(it.nth_back(0), ity.nth_back(0)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + assert_eq!(it.nth_back(0), ity.nth_back(0)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + assert_eq!(it.nth_back(0), ity.nth_back(0)); + assert_eq!(it.clone().nth(0), ity.clone().nth(0)); + + let mut it = xs.iter().skip(2); + assert_eq!(it.nth_back(4), None); + assert_eq!(it.nth_back(0), None); + + let mut it = xs.iter(); + it.by_ref().skip(2).nth_back(3); + assert_eq!(it.next_back(), Some(&1)); + + let mut it = xs.iter(); + it.by_ref().skip(2).nth_back(10); + assert_eq!(it.next_back(), Some(&1)); +} + +#[test] +fn test_skip_non_fused() { + let non_fused = Unfuse::new(0..10); + + // `Skip` would previously exhaust the iterator in this `next` call and then erroneously try to + // advance it further. `Unfuse` tests that this doesn't happen by panicking in that scenario. + let _ = non_fused.skip(20).next(); +} + +#[test] +fn test_skip_non_fused_nth_overflow() { + let non_fused = Unfuse::new(0..10); + + // Ensures that calling skip and `nth` where the sum would overflow does not fail for non-fused + // iterators. + let _ = non_fused.skip(20).nth(usize::MAX); +} + +#[test] +fn test_skip_overflow_wrapping() { + // Test to ensure even on overflowing on `skip+nth` the correct amount of elements are yielded. + struct WrappingIterator(usize); + + impl Iterator for WrappingIterator { + type Item = usize; + + fn next(&mut self) -> core::option::Option { + ::nth(self, 0) + } + + fn nth(&mut self, nth: usize) -> core::option::Option { + self.0 = self.0.wrapping_add(nth.wrapping_add(1)); + Some(self.0) + } + } + + let wrap = WrappingIterator(0); + assert_eq!(wrap.skip(20).nth(usize::MAX), Some(20)); +} diff --git a/library/coretests/tests/iter/adapters/skip_while.rs b/library/coretests/tests/iter/adapters/skip_while.rs new file mode 100644 index 00000000000..929d4f6e64f --- /dev/null +++ b/library/coretests/tests/iter/adapters/skip_while.rs @@ -0,0 +1,50 @@ +use core::iter::*; + +#[test] +fn test_iterator_skip_while() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [15, 16, 17, 19]; + let it = xs.iter().skip_while(|&x| *x < 15); + let mut i = 0; + for x in it { + assert_eq!(*x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +#[test] +fn test_iterator_skip_while_fold() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [15, 16, 17, 19]; + let it = xs.iter().skip_while(|&x| *x < 15); + let i = it.fold(0, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); + + let mut it = xs.iter().skip_while(|&x| *x < 15); + assert_eq!(it.next(), Some(&ys[0])); // process skips before folding + let i = it.fold(1, |i, &x| { + assert_eq!(x, ys[i]); + i + 1 + }); + assert_eq!(i, ys.len()); +} + +#[test] +fn test_skip_while_try_fold() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + fn p(&x: &i32) -> bool { + (x % 10) <= 5 + } + assert_eq!((1..20).skip_while(p).try_fold(7, f), (6..20).try_fold(7, f)); + let mut iter = (1..20).skip_while(p); + assert_eq!(iter.nth(5), Some(11)); + assert_eq!(iter.try_fold(7, f), (12..20).try_fold(7, f)); + + let mut iter = (0..50).skip_while(|&x| (x % 20) < 15); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(23)); +} diff --git a/library/coretests/tests/iter/adapters/step_by.rs b/library/coretests/tests/iter/adapters/step_by.rs new file mode 100644 index 00000000000..6f3300e7a88 --- /dev/null +++ b/library/coretests/tests/iter/adapters/step_by.rs @@ -0,0 +1,301 @@ +use core::iter::*; + +#[test] +fn test_iterator_step_by() { + // Identity + let mut it = (0..).step_by(1).take(3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + + let mut it = (0..).step_by(3).take(4); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(3)); + assert_eq!(it.next(), Some(6)); + assert_eq!(it.next(), Some(9)); + assert_eq!(it.next(), None); + + let mut it = (0..3).step_by(1); + assert_eq!(it.next_back(), Some(2)); + assert_eq!(it.next_back(), Some(1)); + assert_eq!(it.next_back(), Some(0)); + assert_eq!(it.next_back(), None); + + let mut it = (0..11).step_by(3); + assert_eq!(it.next_back(), Some(9)); + assert_eq!(it.next_back(), Some(6)); + assert_eq!(it.next_back(), Some(3)); + assert_eq!(it.next_back(), Some(0)); + assert_eq!(it.next_back(), None); +} + +#[test] +fn test_iterator_step_by_nth() { + let mut it = (0..16).step_by(5); + assert_eq!(it.nth(0), Some(0)); + assert_eq!(it.nth(0), Some(5)); + assert_eq!(it.nth(0), Some(10)); + assert_eq!(it.nth(0), Some(15)); + assert_eq!(it.nth(0), None); + + let it = (0..18).step_by(5); + assert_eq!(it.clone().nth(0), Some(0)); + assert_eq!(it.clone().nth(1), Some(5)); + assert_eq!(it.clone().nth(2), Some(10)); + assert_eq!(it.clone().nth(3), Some(15)); + assert_eq!(it.clone().nth(4), None); + assert_eq!(it.clone().nth(42), None); +} + +#[test] +#[allow(non_local_definitions)] +fn test_iterator_step_by_nth_overflow() { + #[cfg(target_pointer_width = "16")] + type Bigger = u32; + #[cfg(target_pointer_width = "32")] + type Bigger = u64; + #[cfg(target_pointer_width = "64")] + type Bigger = u128; + + #[derive(Clone)] + struct Test(Bigger); + impl Iterator for &mut Test { + type Item = i32; + fn next(&mut self) -> Option { + Some(21) + } + fn nth(&mut self, n: usize) -> Option { + self.0 += n as Bigger + 1; + Some(42) + } + } + + let mut it = Test(0); + let root = usize::MAX >> (usize::BITS / 2); + let n = root + 20; + (&mut it).step_by(n).nth(n); + assert_eq!(it.0, n as Bigger * n as Bigger); + + // large step + let mut it = Test(0); + (&mut it).step_by(usize::MAX).nth(5); + assert_eq!(it.0, (usize::MAX as Bigger) * 5); + + // n + 1 overflows + let mut it = Test(0); + (&mut it).step_by(2).nth(usize::MAX); + assert_eq!(it.0, (usize::MAX as Bigger) * 2); + + // n + 1 overflows + let mut it = Test(0); + (&mut it).step_by(1).nth(usize::MAX); + assert_eq!(it.0, (usize::MAX as Bigger) * 1); +} + +#[test] +fn test_iterator_step_by_nth_try_fold() { + let mut it = (0..).step_by(10); + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it.next(), Some(60)); + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it.next(), Some(90)); + + let mut it = (100..).step_by(10); + assert_eq!(it.try_fold(50, i8::checked_add), None); + assert_eq!(it.next(), Some(110)); + + let mut it = (100..=100).step_by(10); + assert_eq!(it.next(), Some(100)); + assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); +} + +#[test] +fn test_iterator_step_by_nth_back() { + let mut it = (0..16).step_by(5); + assert_eq!(it.nth_back(0), Some(15)); + assert_eq!(it.nth_back(0), Some(10)); + assert_eq!(it.nth_back(0), Some(5)); + assert_eq!(it.nth_back(0), Some(0)); + assert_eq!(it.nth_back(0), None); + + let mut it = (0..16).step_by(5); + assert_eq!(it.next(), Some(0)); // to set `first_take` to `false` + assert_eq!(it.nth_back(0), Some(15)); + assert_eq!(it.nth_back(0), Some(10)); + assert_eq!(it.nth_back(0), Some(5)); + assert_eq!(it.nth_back(0), None); + + let it = || (0..18).step_by(5); + assert_eq!(it().nth_back(0), Some(15)); + assert_eq!(it().nth_back(1), Some(10)); + assert_eq!(it().nth_back(2), Some(5)); + assert_eq!(it().nth_back(3), Some(0)); + assert_eq!(it().nth_back(4), None); + assert_eq!(it().nth_back(42), None); +} + +#[test] +fn test_iterator_step_by_nth_try_rfold() { + let mut it = (0..100).step_by(10); + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it.next_back(), Some(70)); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it.next_back(), Some(30)); + + let mut it = (0..100).step_by(10); + assert_eq!(it.try_rfold(50, i8::checked_add), None); + assert_eq!(it.next_back(), Some(80)); + + let mut it = (100..=100).step_by(10); + assert_eq!(it.next_back(), Some(100)); + assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); +} + +#[test] +#[should_panic] +fn test_iterator_step_by_zero() { + let mut it = (0..).step_by(0); + it.next(); +} + +#[test] +fn test_iterator_step_by_size_hint() { + struct StubSizeHint(usize, Option); + impl Iterator for StubSizeHint { + type Item = (); + fn next(&mut self) -> Option<()> { + self.0 -= 1; + if let Some(ref mut upper) = self.1 { + *upper -= 1; + } + Some(()) + } + fn size_hint(&self) -> (usize, Option) { + (self.0, self.1) + } + } + + // The two checks in each case are needed because the logic + // is different before the first call to `next()`. + + let mut it = StubSizeHint(10, Some(10)).step_by(1); + assert_eq!(it.size_hint(), (10, Some(10))); + it.next(); + assert_eq!(it.size_hint(), (9, Some(9))); + + // exact multiple + let mut it = StubSizeHint(10, Some(10)).step_by(3); + assert_eq!(it.size_hint(), (4, Some(4))); + it.next(); + assert_eq!(it.size_hint(), (3, Some(3))); + + // larger base range, but not enough to get another element + let mut it = StubSizeHint(12, Some(12)).step_by(3); + assert_eq!(it.size_hint(), (4, Some(4))); + it.next(); + assert_eq!(it.size_hint(), (3, Some(3))); + + // smaller base range, so fewer resulting elements + let mut it = StubSizeHint(9, Some(9)).step_by(3); + assert_eq!(it.size_hint(), (3, Some(3))); + it.next(); + assert_eq!(it.size_hint(), (2, Some(2))); + + // infinite upper bound + let mut it = StubSizeHint(usize::MAX, None).step_by(1); + assert_eq!(it.size_hint(), (usize::MAX, None)); + it.next(); + assert_eq!(it.size_hint(), (usize::MAX - 1, None)); + + // still infinite with larger step + let mut it = StubSizeHint(7, None).step_by(3); + assert_eq!(it.size_hint(), (3, None)); + it.next(); + assert_eq!(it.size_hint(), (2, None)); + + // propagates ExactSizeIterator + let a = [1, 2, 3, 4, 5]; + let it = a.iter().step_by(2); + assert_eq!(it.len(), 3); + + // Cannot be TrustedLen as a step greater than one makes an iterator + // with (usize::MAX, None) no longer meet the safety requirements. + // Exception: The inner iterator is known to have a len() <= usize::MAX + trait TrustedLenCheck { + fn test(self) -> bool; + } + impl TrustedLenCheck for T { + default fn test(self) -> bool { + false + } + } + impl TrustedLenCheck for T { + fn test(self) -> bool { + true + } + } + assert!(TrustedLenCheck::test(a.iter())); + assert!(TrustedLenCheck::test(a.iter().step_by(1))); + assert!(TrustedLenCheck::test(a.iter().chain(a.iter()))); + assert!(!TrustedLenCheck::test(a.iter().chain(a.iter()).step_by(1))); +} + +#[test] +fn test_step_by_skip() { + assert_eq!((0..640).step_by(128).skip(1).collect::>(), [128, 256, 384, 512]); + assert_eq!((0..=50).step_by(10).nth(3), Some(30)); + assert_eq!((200..=255u8).step_by(10).nth(3), Some(230)); +} + +struct DeOpt(I); + +impl Iterator for DeOpt { + type Item = I::Item; + + fn next(&mut self) -> core::option::Option { + self.0.next() + } +} + +impl DoubleEndedIterator for DeOpt { + fn next_back(&mut self) -> core::option::Option { + self.0.next_back() + } +} + +#[test] +fn test_step_by_fold_range_specialization() { + macro_rules! t { + ($range:expr, $var: ident, $body:tt) => {{ + // run the same tests for the non-optimized version + let mut $var = DeOpt($range); + $body + } + { + let mut $var = $range; + $body + }}; + } + + t!((1usize..5).step_by(1), r, { + assert_eq!(r.next_back(), Some(4)); + assert_eq!(r.sum::(), 6); + }); + + t!((0usize..4).step_by(2), r, { + assert_eq!(r.next(), Some(0)); + assert_eq!(r.sum::(), 2); + }); + + t!((0usize..5).step_by(2), r, { + assert_eq!(r.next(), Some(0)); + assert_eq!(r.sum::(), 6); + }); + + t!((usize::MAX - 6..usize::MAX).step_by(5), r, { + assert_eq!(r.next(), Some(usize::MAX - 6)); + assert_eq!(r.sum::(), usize::MAX - 1); + }); +} diff --git a/library/coretests/tests/iter/adapters/take.rs b/library/coretests/tests/iter/adapters/take.rs new file mode 100644 index 00000000000..b932059afec --- /dev/null +++ b/library/coretests/tests/iter/adapters/take.rs @@ -0,0 +1,262 @@ +use core::iter::*; +use core::num::NonZero; + +#[test] +fn test_iterator_take() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [0, 1, 2, 3, 5]; + + let mut it = xs.iter().take(ys.len()); + let mut i = 0; + assert_eq!(it.len(), ys.len()); + while let Some(&x) = it.next() { + assert_eq!(x, ys[i]); + i += 1; + assert_eq!(it.len(), ys.len() - i); + } + assert_eq!(i, ys.len()); + assert_eq!(it.len(), 0); + + let mut it = xs.iter().take(ys.len()); + let mut i = 0; + assert_eq!(it.len(), ys.len()); + while let Some(&x) = it.next_back() { + i += 1; + assert_eq!(x, ys[ys.len() - i]); + assert_eq!(it.len(), ys.len() - i); + } + assert_eq!(i, ys.len()); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_iterator_take_nth() { + let xs = [0, 1, 2, 4, 5]; + let mut it = xs.iter(); + { + let mut take = it.by_ref().take(3); + let mut i = 0; + while let Some(&x) = take.nth(0) { + assert_eq!(x, i); + i += 1; + } + } + assert_eq!(it.nth(1), Some(&5)); + assert_eq!(it.nth(0), None); + + let xs = [0, 1, 2, 3, 4]; + let mut it = xs.iter().take(7); + let mut i = 1; + while let Some(&x) = it.nth(1) { + assert_eq!(x, i); + i += 2; + } +} + +#[test] +fn test_iterator_take_nth_back() { + let xs = [0, 1, 2, 4, 5]; + let mut it = xs.iter(); + { + let mut take = it.by_ref().take(3); + let mut i = 0; + while let Some(&x) = take.nth_back(0) { + i += 1; + assert_eq!(x, 3 - i); + } + } + assert_eq!(it.nth_back(0), None); + + let xs = [0, 1, 2, 3, 4]; + let mut it = xs.iter().take(7); + assert_eq!(it.nth_back(1), Some(&3)); + assert_eq!(it.nth_back(1), Some(&1)); + assert_eq!(it.nth_back(1), None); +} + +#[test] +fn test_take_advance_by() { + let mut take = (0..10).take(3); + assert_eq!(take.advance_by(2), Ok(())); + assert_eq!(take.next(), Some(2)); + assert_eq!(take.advance_by(1), Err(NonZero::new(1).unwrap())); + + assert_eq!((0..0).take(10).advance_by(0), Ok(())); + assert_eq!((0..0).take(10).advance_by(1), Err(NonZero::new(1).unwrap())); + assert_eq!((0..10).take(4).advance_by(5), Err(NonZero::new(1).unwrap())); + + let mut take = (0..10).take(3); + assert_eq!(take.advance_back_by(2), Ok(())); + assert_eq!(take.next(), Some(0)); + assert_eq!(take.advance_back_by(1), Err(NonZero::new(1).unwrap())); + + assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZero::new(9).unwrap())); + assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZero::new(1).unwrap())); + assert_eq!((0..0).take(1).advance_back_by(0), Ok(())); + assert_eq!( + (0..usize::MAX).take(100).advance_back_by(usize::MAX), + Err(NonZero::new(usize::MAX - 100).unwrap()) + ); +} + +#[test] +fn test_iterator_take_short() { + let xs = [0, 1, 2, 3]; + + let mut it = xs.iter().take(5); + let mut i = 0; + assert_eq!(it.len(), xs.len()); + while let Some(&x) = it.next() { + assert_eq!(x, xs[i]); + i += 1; + assert_eq!(it.len(), xs.len() - i); + } + assert_eq!(i, xs.len()); + assert_eq!(it.len(), 0); + + let mut it = xs.iter().take(5); + let mut i = 0; + assert_eq!(it.len(), xs.len()); + while let Some(&x) = it.next_back() { + i += 1; + assert_eq!(x, xs[xs.len() - i]); + assert_eq!(it.len(), xs.len() - i); + } + assert_eq!(i, xs.len()); + assert_eq!(it.len(), 0); +} + +#[test] +fn test_take_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((10..30).take(10).try_fold(7, f), (10..20).try_fold(7, f)); + assert_eq!((10..30).take(10).try_rfold(7, f), (10..20).try_rfold(7, f)); + + let mut iter = (10..30).take(20); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(20)); + assert_eq!(iter.try_rfold(0, i8::checked_add), None); + assert_eq!(iter.next_back(), Some(24)); + + let mut iter = (2..20).take(3); + assert_eq!(iter.try_for_each(Err), Err(2)); + assert_eq!(iter.try_for_each(Err), Err(3)); + assert_eq!(iter.try_for_each(Err), Err(4)); + assert_eq!(iter.try_for_each(Err), Ok(())); + + let mut iter = (2..20).take(3).rev(); + assert_eq!(iter.try_for_each(Err), Err(4)); + assert_eq!(iter.try_for_each(Err), Err(3)); + assert_eq!(iter.try_for_each(Err), Err(2)); + assert_eq!(iter.try_for_each(Err), Ok(())); +} + +#[test] +fn test_byref_take_consumed_items() { + let mut inner = 10..90; + + let mut count = 0; + inner.by_ref().take(0).for_each(|_| count += 1); + assert_eq!(count, 0); + assert_eq!(inner, 10..90); + + let mut count = 0; + inner.by_ref().take(10).for_each(|_| count += 1); + assert_eq!(count, 10); + assert_eq!(inner, 20..90); + + let mut count = 0; + inner.by_ref().take(100).for_each(|_| count += 1); + assert_eq!(count, 70); + assert_eq!(inner, 90..90); +} + +#[test] +fn test_exact_size_take_repeat() { + let mut iter = core::iter::repeat(42).take(40); + assert_eq!((40, Some(40)), iter.size_hint()); + assert_eq!(40, iter.len()); + + assert_eq!(Some(42), iter.next()); + assert_eq!((39, Some(39)), iter.size_hint()); + assert_eq!(39, iter.len()); + + assert_eq!(Some(42), iter.next_back()); + assert_eq!((38, Some(38)), iter.size_hint()); + assert_eq!(38, iter.len()); + + assert_eq!(Some(42), iter.nth(3)); + assert_eq!((34, Some(34)), iter.size_hint()); + assert_eq!(34, iter.len()); + + assert_eq!(Some(42), iter.nth_back(3)); + assert_eq!((30, Some(30)), iter.size_hint()); + assert_eq!(30, iter.len()); + + assert_eq!(Ok(()), iter.advance_by(10)); + assert_eq!((20, Some(20)), iter.size_hint()); + assert_eq!(20, iter.len()); + + assert_eq!(Ok(()), iter.advance_back_by(10)); + assert_eq!((10, Some(10)), iter.size_hint()); + assert_eq!(10, iter.len()); +} + +#[test] +fn test_exact_size_take_repeat_with() { + let mut counter = 0; + let mut iter = core::iter::repeat_with(move || { + counter += 1; + counter + }) + .take(40); + assert_eq!((40, Some(40)), iter.size_hint()); + assert_eq!(40, iter.len()); + + assert_eq!(Some(1), iter.next()); + assert_eq!((39, Some(39)), iter.size_hint()); + assert_eq!(39, iter.len()); + + assert_eq!(Some(5), iter.nth(3)); + assert_eq!((35, Some(35)), iter.size_hint()); + assert_eq!(35, iter.len()); + + assert_eq!(Ok(()), iter.advance_by(10)); + assert_eq!((25, Some(25)), iter.size_hint()); + assert_eq!(25, iter.len()); + + assert_eq!(Some(16), iter.next()); + assert_eq!((24, Some(24)), iter.size_hint()); + assert_eq!(24, iter.len()); +} + +// This is https://github.com/rust-lang/rust/issues/104729 with all uses of +// repeat(0) were replaced by repeat(0).take(20). +#[test] +fn test_reverse_on_zip() { + let vec_1 = [1; 10]; + + let zipped_iter = vec_1.iter().copied().zip(core::iter::repeat(0).take(20)); + + // Forward + for (one, zero) in zipped_iter { + assert_eq!((1, 0), (one, zero)); + } + + let rev_vec_iter = vec_1.iter().rev(); + let rev_repeat_iter = std::iter::repeat(0).take(20).rev(); + + // Manual reversed zip + let rev_zipped_iter = rev_vec_iter.zip(rev_repeat_iter); + + for (&one, zero) in rev_zipped_iter { + assert_eq!((1, 0), (one, zero)); + } + + let zipped_iter = vec_1.iter().zip(core::iter::repeat(0).take(20)); + + // Cannot call rev here for automatic reversed zip construction + for (&one, zero) in zipped_iter.rev() { + assert_eq!((1, 0), (one, zero)); + } +} diff --git a/library/coretests/tests/iter/adapters/take_while.rs b/library/coretests/tests/iter/adapters/take_while.rs new file mode 100644 index 00000000000..6f1ebab29b3 --- /dev/null +++ b/library/coretests/tests/iter/adapters/take_while.rs @@ -0,0 +1,29 @@ +use core::iter::*; + +#[test] +fn test_iterator_take_while() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + let ys = [0, 1, 2, 3, 5, 13]; + let it = xs.iter().take_while(|&x| *x < 15); + let mut i = 0; + for x in it { + assert_eq!(*x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); +} + +#[test] +fn test_take_while_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((1..20).take_while(|&x| x != 10).try_fold(7, f), (1..10).try_fold(7, f)); + let mut iter = (1..20).take_while(|&x| x != 10); + assert_eq!(iter.try_fold(0, |x, y| Some(x + y)), Some((1..10).sum())); + assert_eq!(iter.next(), None, "flag should be set"); + let iter = (1..20).take_while(|&x| x != 10); + assert_eq!(iter.fold(0, |x, y| x + y), (1..10).sum()); + + let mut iter = (10..50).take_while(|&x| x != 40); + assert_eq!(iter.try_fold(0, i8::checked_add), None); + assert_eq!(iter.next(), Some(20)); +} diff --git a/library/coretests/tests/iter/adapters/zip.rs b/library/coretests/tests/iter/adapters/zip.rs new file mode 100644 index 00000000000..70392dca0fa --- /dev/null +++ b/library/coretests/tests/iter/adapters/zip.rs @@ -0,0 +1,319 @@ +use core::iter::*; + +use super::*; + +#[test] +fn test_zip_nth() { + let xs = [0, 1, 2, 4, 5]; + let ys = [10, 11, 12]; + + let mut it = xs.iter().zip(&ys); + assert_eq!(it.nth(0), Some((&0, &10))); + assert_eq!(it.nth(1), Some((&2, &12))); + assert_eq!(it.nth(0), None); + + let mut it = xs.iter().zip(&ys); + assert_eq!(it.nth(3), None); + + let mut it = ys.iter().zip(&xs); + assert_eq!(it.nth(3), None); +} + +#[test] +fn test_zip_nth_side_effects() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let value = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })) + .skip(1) + .nth(3); + assert_eq!(value, Some((50, 6000))); + assert_eq!(a, vec![1, 2, 3, 4, 5]); + assert_eq!(b, vec![200, 300, 400, 500, 600]); +} + +#[test] +fn test_zip_next_back_side_effects() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let mut iter = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })); + + // The second iterator is one item longer, so `next_back` is called on it + // one more time. + assert_eq!(iter.next_back(), Some((60, 7000))); + assert_eq!(iter.next_back(), Some((50, 6000))); + assert_eq!(iter.next_back(), Some((40, 5000))); + assert_eq!(iter.next_back(), Some((30, 4000))); + assert_eq!(a, vec![6, 5, 4, 3]); + assert_eq!(b, vec![800, 700, 600, 500, 400]); +} + +#[test] +fn test_zip_nth_back_side_effects() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let value = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })) + .nth_back(3); + assert_eq!(value, Some((30, 4000))); + assert_eq!(a, vec![6, 5, 4, 3]); + assert_eq!(b, vec![800, 700, 600, 500, 400]); +} + +#[test] +fn test_zip_next_back_side_effects_exhausted() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let mut iter = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })); + + iter.next(); + iter.next(); + iter.next(); + iter.next(); + assert_eq!(iter.next_back(), None); + assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + assert_eq!(b, vec![200, 300, 400]); +} + +#[test] +fn test_zip_cloned_sideffectful() { + let xs = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()]; + let ys = [CountClone::new(), CountClone::new()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} + + assert_eq!(&xs, &[1, 1, 1, 0][..]); + assert_eq!(&ys, &[1, 1][..]); + + let xs = [CountClone::new(), CountClone::new()]; + let ys = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} + + assert_eq!(&xs, &[1, 1][..]); + assert_eq!(&ys, &[1, 1, 0, 0][..]); +} + +#[test] +fn test_zip_map_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} + + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + assert_eq!(&ys, &[1, 1, 1, 1]); + + let mut xs = [0; 4]; + let mut ys = [0; 6]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} + + assert_eq!(&xs, &[1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); +} + +#[test] +fn test_zip_map_rev_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + it.next_back(); + } + assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); + assert_eq!(&ys, &[0, 0, 0, 1]); + + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + (&mut it).take(5).count(); + it.next_back(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1]); +} + +#[test] +fn test_zip_nested_sideffectful() { + let mut xs = [0; 6]; + let ys = [0; 4]; + + { + // test that it has the side effect nested inside enumerate + let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); + it.count(); + } + let length_aware = &xs == &[1, 1, 1, 1, 0, 0]; + let probe_first = &xs == &[1, 1, 1, 1, 1, 0]; + + // either implementation is valid according to zip documentation + assert!(length_aware || probe_first); +} + +#[test] +fn test_zip_nth_back_side_effects_exhausted() { + let mut a = Vec::new(); + let mut b = Vec::new(); + let mut iter = [1, 2, 3, 4, 5, 6] + .iter() + .cloned() + .map(|n| { + a.push(n); + n * 10 + }) + .zip([2, 3, 4].iter().cloned().map(|n| { + b.push(n * 100); + n * 1000 + })); + + iter.next(); + iter.next(); + iter.next(); + iter.next(); + assert_eq!(iter.nth_back(0), None); + assert_eq!(a, vec![1, 2, 3, 4, 6, 5]); + assert_eq!(b, vec![200, 300, 400]); +} + +#[test] +fn test_zip_trusted_random_access_composition() { + let a = [0, 1, 2, 3, 4]; + let b = a; + let c = a; + + let a = a.iter().copied(); + let b = b.iter().copied(); + let mut c = c.iter().copied(); + c.next(); + + let mut z1 = a.zip(b); + assert_eq!(z1.next().unwrap(), (0, 0)); + + let mut z2 = z1.zip(c); + fn assert_trusted_random_access(_a: &T) {} + assert_trusted_random_access(&z2); + assert_eq!(z2.next().unwrap(), ((1, 1), 1)); +} + +#[test] +#[cfg(panic = "unwind")] +fn test_zip_trusted_random_access_next_back_drop() { + use std::panic::{AssertUnwindSafe, catch_unwind}; + + let mut counter = 0; + + let it = [42].iter().map(|e| { + let c = counter; + counter += 1; + if c == 0 { + panic!("bomb"); + } + + e + }); + let it2 = [(); 0].iter(); + let mut zip = it.zip(it2); + catch_unwind(AssertUnwindSafe(|| { + zip.next_back(); + })) + .unwrap_err(); + assert!(zip.next().is_none()); + assert_eq!(counter, 1); +} + +#[test] +fn test_double_ended_zip() { + let xs = [1, 2, 3, 4, 5, 6]; + let ys = [1, 2, 3, 7]; + let mut it = xs.iter().cloned().zip(ys); + assert_eq!(it.next(), Some((1, 1))); + assert_eq!(it.next(), Some((2, 2))); + assert_eq!(it.next_back(), Some((4, 7))); + assert_eq!(it.next_back(), Some((3, 3))); + assert_eq!(it.next(), None); +} + +#[test] +fn test_issue_82282() { + fn overflowed_zip(arr: &[i32]) -> impl Iterator { + static UNIT_EMPTY_ARR: [(); 0] = []; + + let mapped = arr.into_iter().map(|i| *i); + let mut zipped = mapped.zip(UNIT_EMPTY_ARR.iter()); + zipped.next(); + zipped + } + + let arr = [1, 2, 3]; + let zip = overflowed_zip(&arr).zip(overflowed_zip(&arr)); + + assert_eq!(zip.size_hint(), (0, Some(0))); + for _ in zip { + panic!(); + } +} + +#[test] +fn test_issue_82291() { + use std::cell::Cell; + + let mut v1 = [()]; + let v2 = [()]; + + let called = Cell::new(0); + + let mut zip = v1 + .iter_mut() + .map(|r| { + called.set(called.get() + 1); + r + }) + .zip(&v2); + + zip.next_back(); + assert_eq!(called.get(), 1); + zip.next(); + assert_eq!(called.get(), 1); +} diff --git a/library/coretests/tests/iter/mod.rs b/library/coretests/tests/iter/mod.rs new file mode 100644 index 00000000000..5b2769d0469 --- /dev/null +++ b/library/coretests/tests/iter/mod.rs @@ -0,0 +1,101 @@ +//! Note +//! ---- +//! You're probably viewing this file because you're adding a test (or you might +//! just be browsing, in that case, hey there!). +//! +//! The iter test suite is split into two big modules, and some miscellaneous +//! smaller modules. The two big modules are `adapters` and `traits`. +//! +//! `adapters` are for methods on `Iterator` that adapt the data inside the +//! iterator, whether it be by emitting another iterator or returning an item +//! from inside the iterator after executing a closure on each item. +//! +//! `traits` are for trait's that extend an `Iterator` (and the `Iterator` +//! trait itself, mostly containing miscellaneous methods). For the most part, +//! if a test in `traits` uses a specific adapter, then it should be moved to +//! that adapter's test file in `adapters`. + +mod adapters; +mod range; +mod sources; +mod traits; + +use core::cell::Cell; +use core::iter::*; + +pub fn is_trusted_len(_: I) {} + +#[test] +fn test_multi_iter() { + let xs = [1, 2, 3, 4]; + let ys = [4, 3, 2, 1]; + assert!(xs.iter().eq(ys.iter().rev())); + assert!(xs.iter().lt(xs.iter().skip(2))); +} + +#[test] +fn test_counter_from_iter() { + let it = (0..).step_by(5).take(10); + let xs: Vec = FromIterator::from_iter(it); + assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); +} + +#[test] +fn test_functor_laws() { + // identity: + fn identity(x: T) -> T { + x + } + assert_eq!((0..10).map(identity).sum::(), (0..10).sum()); + + // composition: + fn f(x: usize) -> usize { + x + 3 + } + fn g(x: usize) -> usize { + x * 2 + } + fn h(x: usize) -> usize { + g(f(x)) + } + assert_eq!((0..10).map(f).map(g).sum::(), (0..10).map(h).sum()); +} + +#[test] +fn test_monad_laws_left_identity() { + fn f(x: usize) -> impl Iterator { + (0..10).map(move |y| x * y) + } + assert_eq!(once(42).flat_map(f.clone()).sum::(), f(42).sum()); +} + +#[test] +fn test_monad_laws_right_identity() { + assert_eq!((0..10).flat_map(|x| once(x)).sum::(), (0..10).sum()); +} + +#[test] +fn test_monad_laws_associativity() { + fn f(x: usize) -> impl Iterator { + 0..x + } + fn g(x: usize) -> impl Iterator { + (0..x).rev() + } + assert_eq!( + (0..10).flat_map(f).flat_map(g).sum::(), + (0..10).flat_map(|x| f(x).flat_map(g)).sum::() + ); +} + +#[test] +pub fn extend_for_unit() { + let mut x = 0; + { + let iter = (0..5).map(|_| { + x += 1; + }); + ().extend(iter); + } + assert_eq!(x, 5); +} diff --git a/library/coretests/tests/iter/range.rs b/library/coretests/tests/iter/range.rs new file mode 100644 index 00000000000..d5d2b8bf2b0 --- /dev/null +++ b/library/coretests/tests/iter/range.rs @@ -0,0 +1,504 @@ +use core::ascii::Char as AsciiChar; +use core::num::NonZero; + +use super::*; + +#[test] +fn test_range() { + assert_eq!((0..5).collect::>(), [0, 1, 2, 3, 4]); + assert_eq!((-10..-1).collect::>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]); + assert_eq!((0..5).rev().collect::>(), [4, 3, 2, 1, 0]); + assert_eq!((200..-5).count(), 0); + assert_eq!((200..-5).rev().count(), 0); + assert_eq!((200..200).count(), 0); + assert_eq!((200..200).rev().count(), 0); + + assert_eq!((0..100).size_hint(), (100, Some(100))); + // this test is only meaningful when sizeof usize < sizeof u64 + assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1))); + assert_eq!((-10..-1).size_hint(), (9, Some(9))); + assert_eq!((-1..-10).size_hint(), (0, Some(0))); + + assert_eq!((-70..58).size_hint(), (128, Some(128))); + assert_eq!((-128..127).size_hint(), (255, Some(255))); + assert_eq!( + (-2..isize::MAX).size_hint(), + (isize::MAX as usize + 2, Some(isize::MAX as usize + 2)) + ); +} + +#[test] +fn test_char_range() { + // Miri is too slow + let from = if cfg!(miri) { char::from_u32(0xD800 - 10).unwrap() } else { '\0' }; + let to = if cfg!(miri) { char::from_u32(0xDFFF + 10).unwrap() } else { char::MAX }; + assert!((from..=to).eq((from as u32..=to as u32).filter_map(char::from_u32))); + assert!((from..=to).rev().eq((from as u32..=to as u32).filter_map(char::from_u32).rev())); + + assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2); + assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2))); + assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1); + assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1))); +} + +#[test] +fn test_ascii_char_range() { + let from = AsciiChar::Null; + let to = AsciiChar::Delete; + assert!((from..=to).eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8))); + assert!((from..=to).rev().eq((from as u8..=to as u8).filter_map(AsciiChar::from_u8).rev())); + + assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).count(), 26); + assert_eq!((AsciiChar::CapitalA..=AsciiChar::CapitalZ).size_hint(), (26, Some(26))); + assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).count(), 26); + assert_eq!((AsciiChar::SmallA..=AsciiChar::SmallZ).size_hint(), (26, Some(26))); + assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).count(), 10); + assert_eq!((AsciiChar::Digit0..=AsciiChar::Digit9).size_hint(), (10, Some(10))); +} + +#[test] +fn test_range_exhaustion() { + let mut r = 10..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 10..10); + + let mut r = 10..12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert!(r.is_empty()); + assert_eq!(r, 12..12); + assert_eq!(r.next(), None); + + let mut r = 10..12; + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r, 10..10); + assert_eq!(r.next_back(), None); + + let mut r = 100..10; + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..10); +} + +#[test] +fn test_range_inclusive_exhaustion() { + let mut r = 10..=10; + assert_eq!(r.next(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); + + assert_eq!(*r.start(), 10); + assert_eq!(*r.end(), 10); + assert_ne!(r, 10..=10); + + let mut r = 10..=10; + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + + assert_eq!(*r.start(), 10); + assert_eq!(*r.end(), 10); + assert_ne!(r, 10..=10); + + let mut r = 10..=12; + assert_eq!(r.next(), Some(10)); + assert_eq!(r.next(), Some(11)); + assert_eq!(r.next(), Some(12)); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + + let mut r = 10..=12; + assert_eq!(r.next_back(), Some(12)); + assert_eq!(r.next_back(), Some(11)); + assert_eq!(r.next_back(), Some(10)); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + + let mut r = 10..=12; + assert_eq!(r.nth(2), Some(12)); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + + let mut r = 10..=12; + assert_eq!(r.nth(5), None); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + + let mut r = 100..=10; + assert_eq!(r.next(), None); + assert!(r.is_empty()); + assert_eq!(r.next(), None); + assert_eq!(r.next(), None); + assert_eq!(r, 100..=10); + + let mut r = 100..=10; + assert_eq!(r.next_back(), None); + assert!(r.is_empty()); + assert_eq!(r.next_back(), None); + assert_eq!(r.next_back(), None); + assert_eq!(r, 100..=10); +} + +#[test] +fn test_range_nth() { + assert_eq!((10..15).nth(0), Some(10)); + assert_eq!((10..15).nth(1), Some(11)); + assert_eq!((10..15).nth(4), Some(14)); + assert_eq!((10..15).nth(5), None); + + let mut r = 10..20; + assert_eq!(r.nth(2), Some(12)); + assert_eq!(r, 13..20); + assert_eq!(r.nth(2), Some(15)); + assert_eq!(r, 16..20); + assert_eq!(r.nth(10), None); + assert_eq!(r, 20..20); +} + +#[test] +fn test_range_nth_back() { + assert_eq!((10..15).nth_back(0), Some(14)); + assert_eq!((10..15).nth_back(1), Some(13)); + assert_eq!((10..15).nth_back(4), Some(10)); + assert_eq!((10..15).nth_back(5), None); + assert_eq!((-120..80_i8).nth_back(199), Some(-120)); + + let mut r = 10..20; + assert_eq!(r.nth_back(2), Some(17)); + assert_eq!(r, 10..17); + assert_eq!(r.nth_back(2), Some(14)); + assert_eq!(r, 10..14); + assert_eq!(r.nth_back(10), None); + assert_eq!(r, 10..10); +} + +#[test] +fn test_range_from_nth() { + assert_eq!((10..).nth(0), Some(10)); + assert_eq!((10..).nth(1), Some(11)); + assert_eq!((10..).nth(4), Some(14)); + + let mut r = 10..; + assert_eq!(r.nth(2), Some(12)); + assert_eq!(r, 13..); + assert_eq!(r.nth(2), Some(15)); + assert_eq!(r, 16..); + assert_eq!(r.nth(10), Some(26)); + assert_eq!(r, 27..); + + assert_eq!((0..).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_range_from_take() { + let mut it = (0..).take(3); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), Some(1)); + assert_eq!(it.next(), Some(2)); + assert_eq!(it.next(), None); + is_trusted_len((0..).take(3)); + assert_eq!((0..).take(3).size_hint(), (3, Some(3))); + assert_eq!((0..).take(0).size_hint(), (0, Some(0))); + assert_eq!((0..).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_range_from_take_collect() { + let v: Vec<_> = (0..).take(3).collect(); + assert_eq!(v, vec![0, 1, 2]); +} + +#[test] +fn test_range_inclusive_nth() { + assert_eq!((10..=15).nth(0), Some(10)); + assert_eq!((10..=15).nth(1), Some(11)); + assert_eq!((10..=15).nth(5), Some(15)); + assert_eq!((10..=15).nth(6), None); + + let mut exhausted_via_next = 10_u8..=20; + while exhausted_via_next.next().is_some() {} + + let mut r = 10_u8..=20; + assert_eq!(r.nth(2), Some(12)); + assert_eq!(r, 13..=20); + assert_eq!(r.nth(2), Some(15)); + assert_eq!(r, 16..=20); + assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); + assert_eq!(r.nth(10), None); + assert_eq!(r.is_empty(), true); + assert_eq!(r, exhausted_via_next); + assert_eq!(ExactSizeIterator::is_empty(&r), true); +} + +#[test] +fn test_range_inclusive_nth_back() { + assert_eq!((10..=15).nth_back(0), Some(15)); + assert_eq!((10..=15).nth_back(1), Some(14)); + assert_eq!((10..=15).nth_back(5), Some(10)); + assert_eq!((10..=15).nth_back(6), None); + assert_eq!((-120..=80_i8).nth_back(200), Some(-120)); + + let mut exhausted_via_next_back = 10_u8..=20; + while exhausted_via_next_back.next_back().is_some() {} + + let mut r = 10_u8..=20; + assert_eq!(r.nth_back(2), Some(18)); + assert_eq!(r, 10..=17); + assert_eq!(r.nth_back(2), Some(15)); + assert_eq!(r, 10..=14); + assert_eq!(r.is_empty(), false); + assert_eq!(ExactSizeIterator::is_empty(&r), false); + assert_eq!(r.nth_back(10), None); + assert_eq!(r.is_empty(), true); + assert_eq!(r, exhausted_via_next_back); + assert_eq!(ExactSizeIterator::is_empty(&r), true); +} + +#[test] +fn test_range_len() { + assert_eq!((0..10_u8).len(), 10); + assert_eq!((9..10_u8).len(), 1); + assert_eq!((10..10_u8).len(), 0); + assert_eq!((11..10_u8).len(), 0); + assert_eq!((100..10_u8).len(), 0); +} + +#[test] +fn test_range_inclusive_len() { + assert_eq!((0..=10_u8).len(), 11); + assert_eq!((9..=10_u8).len(), 2); + assert_eq!((10..=10_u8).len(), 1); + assert_eq!((11..=10_u8).len(), 0); + assert_eq!((100..=10_u8).len(), 0); +} + +#[test] +fn test_range_step() { + #![allow(deprecated)] + + assert_eq!((0..20).step_by(5).collect::>(), [0, 5, 10, 15]); + assert_eq!((1..21).rev().step_by(5).collect::>(), [20, 15, 10, 5]); + assert_eq!((1..21).rev().step_by(6).collect::>(), [20, 14, 8, 2]); + assert_eq!((200..255).step_by(50).collect::>(), [200, 250]); + assert_eq!((200..-5).step_by(1).collect::>(), []); + assert_eq!((200..200).step_by(1).collect::>(), []); + + assert_eq!((0..20).step_by(1).size_hint(), (20, Some(20))); + assert_eq!((0..20).step_by(21).size_hint(), (1, Some(1))); + assert_eq!((0..20).step_by(5).size_hint(), (4, Some(4))); + assert_eq!((1..21).rev().step_by(5).size_hint(), (4, Some(4))); + assert_eq!((1..21).rev().step_by(6).size_hint(), (4, Some(4))); + assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0))); + assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0))); + assert_eq!((i8::MIN..i8::MAX).step_by(-(i8::MIN as i32) as usize).size_hint(), (2, Some(2))); + assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX as usize).size_hint(), (3, Some(3))); + assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_range_advance_by() { + let mut r = 0..usize::MAX; + assert_eq!(Ok(()), r.advance_by(0)); + assert_eq!(Ok(()), r.advance_back_by(0)); + + assert_eq!(r.len(), usize::MAX); + + assert_eq!(Ok(()), r.advance_by(1)); + assert_eq!(Ok(()), r.advance_back_by(1)); + + assert_eq!((r.start, r.end), (1, usize::MAX - 1)); + + assert_eq!(Err(NonZero::new(2).unwrap()), r.advance_by(usize::MAX)); + + assert_eq!(Ok(()), r.advance_by(0)); + assert_eq!(Ok(()), r.advance_back_by(0)); + + let mut r = 0u128..u128::MAX; + + assert_eq!(Ok(()), r.advance_by(usize::MAX)); + assert_eq!(Ok(()), r.advance_back_by(usize::MAX)); + + assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128)); + + // issue 122420, Step::forward_unchecked was unsound for signed integers + let mut r = -128i8..127; + assert_eq!(Ok(()), r.advance_by(200)); + assert_eq!(r.next(), Some(72)); +} + +#[test] +fn test_range_inclusive_step() { + assert_eq!((0..=50).step_by(10).collect::>(), [0, 10, 20, 30, 40, 50]); + assert_eq!((0..=5).step_by(1).collect::>(), [0, 1, 2, 3, 4, 5]); + assert_eq!((200..=255u8).step_by(10).collect::>(), [200, 210, 220, 230, 240, 250]); + assert_eq!((250..=255u8).step_by(1).collect::>(), [250, 251, 252, 253, 254, 255]); +} + +#[test] +fn test_range_last_max() { + assert_eq!((0..20).last(), Some(19)); + assert_eq!((-20..0).last(), Some(-1)); + assert_eq!((5..5).last(), None); + + assert_eq!((0..20).max(), Some(19)); + assert_eq!((-20..0).max(), Some(-1)); + assert_eq!((5..5).max(), None); +} + +#[test] +fn test_range_inclusive_last_max() { + assert_eq!((0..=20).last(), Some(20)); + assert_eq!((-20..=0).last(), Some(0)); + assert_eq!((5..=5).last(), Some(5)); + let mut r = 10..=10; + r.next(); + assert_eq!(r.last(), None); + + assert_eq!((0..=20).max(), Some(20)); + assert_eq!((-20..=0).max(), Some(0)); + assert_eq!((5..=5).max(), Some(5)); + let mut r = 10..=10; + r.next(); + assert_eq!(r.max(), None); +} + +#[test] +fn test_range_min() { + assert_eq!((0..20).min(), Some(0)); + assert_eq!((-20..0).min(), Some(-20)); + assert_eq!((5..5).min(), None); +} + +#[test] +fn test_range_inclusive_min() { + assert_eq!((0..=20).min(), Some(0)); + assert_eq!((-20..=0).min(), Some(-20)); + assert_eq!((5..=5).min(), Some(5)); + let mut r = 10..=10; + r.next(); + assert_eq!(r.min(), None); +} + +#[test] +fn test_range_inclusive_folds() { + assert_eq!((1..=10).sum::(), 55); + assert_eq!((1..=10).rev().sum::(), 55); + + let mut it = 44..=50; + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it, 47..=50); + assert_eq!(it.try_fold(0, i8::checked_add), None); + assert_eq!(it, 50..=50); + assert_eq!(it.try_fold(0, i8::checked_add), Some(50)); + assert!(it.is_empty()); + assert_eq!(it.try_fold(0, i8::checked_add), Some(0)); + assert!(it.is_empty()); + + let mut it = 40..=47; + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it, 40..=44); + assert_eq!(it.try_rfold(0, i8::checked_add), None); + assert_eq!(it, 40..=41); + assert_eq!(it.try_rfold(0, i8::checked_add), Some(81)); + assert!(it.is_empty()); + assert_eq!(it.try_rfold(0, i8::checked_add), Some(0)); + assert!(it.is_empty()); + + let mut it = 10..=20; + assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(165)); + assert!(it.is_empty()); + assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(0)); + assert!(it.is_empty()); + + let mut it = 10..=20; + assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(165)); + assert!(it.is_empty()); + assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(0)); + assert!(it.is_empty()); +} + +#[test] +fn test_range_size_hint() { + assert_eq!((0..0usize).size_hint(), (0, Some(0))); + assert_eq!((0..100usize).size_hint(), (100, Some(100))); + assert_eq!((0..usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); + + let umax = u128::try_from(usize::MAX).unwrap(); + assert_eq!((0..0u128).size_hint(), (0, Some(0))); + assert_eq!((0..100u128).size_hint(), (100, Some(100))); + assert_eq!((0..umax).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((0..umax + 1).size_hint(), (usize::MAX, None)); + + assert_eq!((0..0isize).size_hint(), (0, Some(0))); + assert_eq!((-100..100isize).size_hint(), (200, Some(200))); + assert_eq!((isize::MIN..isize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); + + let imin = i128::try_from(isize::MIN).unwrap(); + let imax = i128::try_from(isize::MAX).unwrap(); + assert_eq!((0..0i128).size_hint(), (0, Some(0))); + assert_eq!((-100..100i128).size_hint(), (200, Some(200))); + assert_eq!((imin..imax).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((imin..imax + 1).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_range_inclusive_size_hint() { + assert_eq!((1..=0usize).size_hint(), (0, Some(0))); + assert_eq!((0..=0usize).size_hint(), (1, Some(1))); + assert_eq!((0..=100usize).size_hint(), (101, Some(101))); + assert_eq!((0..=usize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((0..=usize::MAX).size_hint(), (usize::MAX, None)); + + let umax = u128::try_from(usize::MAX).unwrap(); + assert_eq!((1..=0u128).size_hint(), (0, Some(0))); + assert_eq!((0..=0u128).size_hint(), (1, Some(1))); + assert_eq!((0..=100u128).size_hint(), (101, Some(101))); + assert_eq!((0..=umax - 1).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((0..=umax).size_hint(), (usize::MAX, None)); + assert_eq!((0..=umax + 1).size_hint(), (usize::MAX, None)); + + assert_eq!((0..=-1isize).size_hint(), (0, Some(0))); + assert_eq!((0..=0isize).size_hint(), (1, Some(1))); + assert_eq!((-100..=100isize).size_hint(), (201, Some(201))); + assert_eq!((isize::MIN..=isize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((isize::MIN..=isize::MAX).size_hint(), (usize::MAX, None)); + + let imin = i128::try_from(isize::MIN).unwrap(); + let imax = i128::try_from(isize::MAX).unwrap(); + assert_eq!((0..=-1i128).size_hint(), (0, Some(0))); + assert_eq!((0..=0i128).size_hint(), (1, Some(1))); + assert_eq!((-100..=100i128).size_hint(), (201, Some(201))); + assert_eq!((imin..=imax - 1).size_hint(), (usize::MAX, Some(usize::MAX))); + assert_eq!((imin..=imax).size_hint(), (usize::MAX, None)); + assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_range_trusted_random_access() { + let mut range = 0..10; + unsafe { + assert_eq!(range.next(), Some(0)); + assert_eq!(range.__iterator_get_unchecked(0), 1); + assert_eq!(range.__iterator_get_unchecked(1), 2); + } +} + +#[test] +fn test_double_ended_range() { + assert_eq!((11..14).rev().collect::>(), [13, 12, 11]); + for _ in (10..0).rev() { + panic!("unreachable"); + } + + assert_eq!((11..14).rev().collect::>(), [13, 12, 11]); + for _ in (10..0).rev() { + panic!("unreachable"); + } +} diff --git a/library/coretests/tests/iter/sources.rs b/library/coretests/tests/iter/sources.rs new file mode 100644 index 00000000000..506febaa056 --- /dev/null +++ b/library/coretests/tests/iter/sources.rs @@ -0,0 +1,182 @@ +use core::iter::*; + +use super::*; + +#[test] +fn test_repeat() { + let mut it = repeat(42); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(repeat(42).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_take() { + let mut it = repeat(42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat(42).take(3)); + assert_eq!(repeat(42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat(42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat(42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_take_collect() { + let v: Vec<_> = repeat(42).take(3).collect(); + assert_eq!(v, vec![42, 42, 42]); +} + +#[test] +fn test_repeat_with() { + #[derive(PartialEq, Debug)] + struct NotClone(usize); + let mut it = repeat_with(|| NotClone(42)); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(it.next(), Some(NotClone(42))); + assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); +} + +#[test] +fn test_repeat_with_take() { + let mut it = repeat_with(|| 42).take(3); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); + is_trusted_len(repeat_with(|| 42).take(3)); + assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3))); + assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0))); + assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX))); +} + +#[test] +fn test_repeat_with_take_collect() { + let mut curr = 1; + let v: Vec<_> = repeat_with(|| { + let tmp = curr; + curr *= 2; + tmp + }) + .take(5) + .collect(); + assert_eq!(v, vec![1, 2, 4, 8, 16]); +} + +#[test] +fn test_successors() { + let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); + assert_eq!(powers_of_10.by_ref().collect::>(), &[1, 10, 100, 1_000, 10_000]); + assert_eq!(powers_of_10.next(), None); + + let mut empty = successors(None::, |_| unimplemented!()); + assert_eq!(empty.next(), None); + assert_eq!(empty.next(), None); +} + +#[test] +fn test_once() { + let mut it = once(42); + assert_eq!(it.next(), Some(42)); + assert_eq!(it.next(), None); +} + +#[test] +fn test_once_with() { + let count = Cell::new(0); + let mut it = once_with(|| { + count.set(count.get() + 1); + 42 + }); + + assert_eq!(count.get(), 0); + assert_eq!(it.next(), Some(42)); + assert_eq!(count.get(), 1); + assert_eq!(it.next(), None); + assert_eq!(count.get(), 1); + assert_eq!(it.next(), None); + assert_eq!(count.get(), 1); +} + +#[test] +fn test_empty() { + let mut it = empty::(); + assert_eq!(it.next(), None); +} + +#[test] +fn test_repeat_n_drop() { + #[derive(Clone, Debug)] + struct DropCounter<'a>(&'a Cell); + impl Drop for DropCounter<'_> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + // `repeat_n(x, 0)` drops `x` immediately + let count = Cell::new(0); + let item = DropCounter(&count); + let mut it = repeat_n(item, 0); + assert_eq!(count.get(), 1); + assert!(it.next().is_none()); + assert_eq!(count.get(), 1); + drop(it); + assert_eq!(count.get(), 1); + + // Dropping the iterator needs to drop the item if it's non-empty + let count = Cell::new(0); + let item = DropCounter(&count); + let it = repeat_n(item, 3); + assert_eq!(count.get(), 0); + drop(it); + assert_eq!(count.get(), 1); + + // Dropping the iterator doesn't drop the item if it was exhausted + let count = Cell::new(0); + let item = DropCounter(&count); + let mut it = repeat_n(item, 3); + assert_eq!(count.get(), 0); + let x0 = it.next().unwrap(); + assert_eq!(count.get(), 0); + let x1 = it.next().unwrap(); + assert_eq!(count.get(), 0); + let x2 = it.next().unwrap(); + assert_eq!(count.get(), 0); + assert!(it.next().is_none()); + assert_eq!(count.get(), 0); + assert!(it.next().is_none()); + assert_eq!(count.get(), 0); + drop(it); + assert_eq!(count.get(), 0); + drop((x0, x1, x2)); + assert_eq!(count.get(), 3); +} + +#[test] +fn test_repeat_n_soundness() { + let x = std::iter::repeat_n(String::from("use after free"), 0); + println!("{x:?}"); + + pub struct PanicOnClone; + + impl Clone for PanicOnClone { + fn clone(&self) -> Self { + unreachable!() + } + } + + // `repeat_n` should drop the element immediately if `count` is zero. + // `Clone` should then not try to clone the element. + let x = std::iter::repeat_n(PanicOnClone, 0); + let _ = x.clone(); + + let mut y = std::iter::repeat_n(Box::new(0), 1); + let x = y.next().unwrap(); + let _z = y; + assert_eq!(0, *x); +} diff --git a/library/coretests/tests/iter/traits/accum.rs b/library/coretests/tests/iter/traits/accum.rs new file mode 100644 index 00000000000..f3eeb31fe58 --- /dev/null +++ b/library/coretests/tests/iter/traits/accum.rs @@ -0,0 +1,66 @@ +use core::iter::*; + +#[test] +fn test_iterator_sum() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().cloned().sum::(), 6); + assert_eq!(v.iter().cloned().sum::(), 55); + assert_eq!(v[..0].iter().cloned().sum::(), 0); +} + +#[test] +fn test_iterator_sum_result() { + let v: &[Result] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().sum::>(), Ok(10)); + let v: &[Result] = &[Ok(1), Err(()), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().sum::>(), Err(())); + + #[derive(PartialEq, Debug)] + struct S(Result); + + impl Sum> for S { + fn sum>>(mut iter: I) -> Self { + // takes the sum by repeatedly calling `next` on `iter`, + // thus testing that repeated calls to `ResultShunt::try_fold` + // produce the expected results + Self(iter.by_ref().sum()) + } + } + + let v: &[Result] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().sum::(), S(Ok(10))); + let v: &[Result] = &[Ok(1), Err(()), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().sum::(), S(Err(()))); +} + +#[test] +fn test_iterator_sum_option() { + let v: &[Option] = &[Some(1), Some(2), Some(3), Some(4)]; + assert_eq!(v.iter().cloned().sum::>(), Some(10)); + let v: &[Option] = &[Some(1), None, Some(3), Some(4)]; + assert_eq!(v.iter().cloned().sum::>(), None); +} + +#[test] +fn test_iterator_product() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().cloned().product::(), 0); + assert_eq!(v[1..5].iter().cloned().product::(), 24); + assert_eq!(v[..0].iter().cloned().product::(), 1); +} + +#[test] +fn test_iterator_product_result() { + let v: &[Result] = &[Ok(1), Ok(2), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().product::>(), Ok(24)); + let v: &[Result] = &[Ok(1), Err(()), Ok(3), Ok(4)]; + assert_eq!(v.iter().cloned().product::>(), Err(())); +} + +#[test] +fn test_iterator_product_option() { + let v: &[Option] = &[Some(1), Some(2), Some(3), Some(4)]; + assert_eq!(v.iter().cloned().product::>(), Some(24)); + let v: &[Option] = &[Some(1), None, Some(3), Some(4)]; + assert_eq!(v.iter().cloned().product::>(), None); +} diff --git a/library/coretests/tests/iter/traits/double_ended.rs b/library/coretests/tests/iter/traits/double_ended.rs new file mode 100644 index 00000000000..00ef4a6e6a9 --- /dev/null +++ b/library/coretests/tests/iter/traits/double_ended.rs @@ -0,0 +1,91 @@ +//! Note +//! ---- +//! You're probably viewing this file because you're adding a test (or you might +//! just be browsing, in that case, hey there!). +//! +//! If you've made a test that happens to use one of DoubleEnded's methods, but +//! it tests another adapter or trait, you should *add it to the adapter or +//! trait's test file*. +//! +//! Some examples would be `adapters::cloned::test_cloned_try_folds` or +//! `adapters::flat_map::test_double_ended_flat_map`, which use `try_fold` and +//! `next_back`, but test their own adapter. + +#[test] +fn test_iterator_rev_nth_back() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]); + } + assert_eq!(v.iter().rev().nth_back(v.len()), None); +} + +#[test] +fn test_iterator_rev_nth() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]); + } + assert_eq!(v.iter().rev().nth(v.len()), None); +} + +#[test] +fn test_rev() { + let xs = [2, 4, 6, 8, 10, 12, 14, 16]; + let mut it = xs.iter(); + it.next(); + it.next(); + assert!(it.rev().cloned().collect::>() == vec![16, 14, 12, 10, 8, 6]); +} + +#[test] +fn test_rev_try_folds() { + let f = &|acc, x| i32::checked_add(2 * acc, x); + assert_eq!((1..10).rev().try_fold(7, f), (1..10).try_rfold(7, f)); + assert_eq!((1..10).rev().try_rfold(7, f), (1..10).try_fold(7, f)); + + let a = [10, 20, 30, 40, 100, 60, 70, 80, 90]; + let mut iter = a.iter().rev(); + assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next(), Some(&70)); + let mut iter = a.iter().rev(); + assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next_back(), Some(&60)); +} + +#[test] +fn test_rposition() { + fn f(xy: &(isize, char)) -> bool { + let (_x, y) = *xy; + y == 'b' + } + fn g(xy: &(isize, char)) -> bool { + let (_x, y) = *xy; + y == 'd' + } + let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + + assert_eq!(v.iter().rposition(f), Some(3)); + assert!(v.iter().rposition(g).is_none()); +} + +#[test] +fn test_rev_rposition() { + let v = [0, 0, 1, 1]; + assert_eq!(v.iter().rev().rposition(|&x| x == 1), Some(1)); +} + +#[test] +#[should_panic] +fn test_rposition_panic() { + let u = (Box::new(0), Box::new(0)); + let v: [(Box<_>, Box<_>); 4] = [u.clone(), u.clone(), u.clone(), u]; + let mut i = 0; + v.iter().rposition(|_elt| { + if i == 2 { + panic!() + } + i += 1; + false + }); +} diff --git a/library/coretests/tests/iter/traits/iterator.rs b/library/coretests/tests/iter/traits/iterator.rs new file mode 100644 index 00000000000..e31d2e15b6d --- /dev/null +++ b/library/coretests/tests/iter/traits/iterator.rs @@ -0,0 +1,651 @@ +use core::num::NonZero; + +/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped +/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min` +/// return the correct element if some of them are equal. +#[derive(Debug)] +struct Mod3(i32); + +impl PartialEq for Mod3 { + fn eq(&self, other: &Self) -> bool { + self.0 % 3 == other.0 % 3 + } +} + +impl Eq for Mod3 {} + +impl PartialOrd for Mod3 { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Mod3 { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + (self.0 % 3).cmp(&(other.0 % 3)) + } +} + +#[test] +fn test_lt() { + let empty: [isize; 0] = []; + let xs = [1, 2, 3]; + let ys = [1, 2, 0]; + + assert!(!xs.iter().lt(ys.iter())); + assert!(!xs.iter().le(ys.iter())); + assert!(xs.iter().gt(ys.iter())); + assert!(xs.iter().ge(ys.iter())); + + assert!(ys.iter().lt(xs.iter())); + assert!(ys.iter().le(xs.iter())); + assert!(!ys.iter().gt(xs.iter())); + assert!(!ys.iter().ge(xs.iter())); + + assert!(empty.iter().lt(xs.iter())); + assert!(empty.iter().le(xs.iter())); + assert!(!empty.iter().gt(xs.iter())); + assert!(!empty.iter().ge(xs.iter())); + + // Sequence with NaN + let u = [1.0f64, 2.0]; + let v = [0.0f64 / 0.0, 3.0]; + + assert!(!u.iter().lt(v.iter())); + assert!(!u.iter().le(v.iter())); + assert!(!u.iter().gt(v.iter())); + assert!(!u.iter().ge(v.iter())); + + let a = [0.0f64 / 0.0]; + let b = [1.0f64]; + let c = [2.0f64]; + + assert!(a.iter().lt(b.iter()) == (a[0] < b[0])); + assert!(a.iter().le(b.iter()) == (a[0] <= b[0])); + assert!(a.iter().gt(b.iter()) == (a[0] > b[0])); + assert!(a.iter().ge(b.iter()) == (a[0] >= b[0])); + + assert!(c.iter().lt(b.iter()) == (c[0] < b[0])); + assert!(c.iter().le(b.iter()) == (c[0] <= b[0])); + assert!(c.iter().gt(b.iter()) == (c[0] > b[0])); + assert!(c.iter().ge(b.iter()) == (c[0] >= b[0])); +} + +#[test] +fn test_cmp_by() { + use core::cmp::Ordering; + + let f = |x: i32, y: i32| (x * x).cmp(&y); + let xs = || [1, 2, 3, 4].iter().copied(); + let ys = || [1, 4, 16].iter().copied(); + + assert_eq!(xs().cmp_by(ys(), f), Ordering::Less); + assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater); + assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal); + assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater); + assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less); + assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater); +} + +#[test] +fn test_partial_cmp_by() { + use core::cmp::Ordering; + + let f = |x: i32, y: i32| (x * x).partial_cmp(&y); + let xs = || [1, 2, 3, 4].iter().copied(); + let ys = || [1, 4, 16].iter().copied(); + + assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less)); + assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); + assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal)); + assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater)); + assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less)); + assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater)); + + let f = |x: f64, y: f64| (x * x).partial_cmp(&y); + let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied(); + let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied(); + + assert_eq!(xs().partial_cmp_by(ys(), f), None); + assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater)); +} + +#[test] +fn test_eq_by() { + let f = |x: i32, y: i32| x * x == y; + let xs = || [1, 2, 3, 4].iter().copied(); + let ys = || [1, 4, 9, 16].iter().copied(); + + assert!(xs().eq_by(ys(), f)); + assert!(!ys().eq_by(xs(), f)); + assert!(!xs().eq_by(xs(), f)); + assert!(!ys().eq_by(ys(), f)); + + assert!(!xs().take(3).eq_by(ys(), f)); + assert!(!xs().eq_by(ys().take(3), f)); + assert!(xs().take(3).eq_by(ys().take(3), f)); +} + +#[test] +fn test_iterator_nth() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().nth(i).unwrap(), &v[i]); + } + assert_eq!(v.iter().nth(v.len()), None); +} + +#[test] +fn test_iterator_nth_back() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]); + } + assert_eq!(v.iter().nth_back(v.len()), None); +} + +#[test] +fn test_iterator_advance_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.next().unwrap(), &v[i]); + assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap())); + } + + assert_eq!(v.iter().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_by(100), Err(NonZero::new(100 - v.len()).unwrap())); +} + +#[test] +fn test_iterator_advance_back_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]); + assert_eq!(iter.advance_back_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap())); + } + + assert_eq!(v.iter().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_back_by(100), Err(NonZero::new(100 - v.len()).unwrap())); +} + +#[test] +fn test_iterator_rev_advance_back_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter().rev(); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.next_back().unwrap(), &v[i]); + assert_eq!(iter.advance_back_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap())); + } + + assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_back_by(100), Err(NonZero::new(100 - v.len()).unwrap())); +} + +#[test] +fn test_iterator_last() { + let v: &[_] = &[0, 1, 2, 3, 4]; + assert_eq!(v.iter().last().unwrap(), &4); + assert_eq!(v[..1].iter().last().unwrap(), &0); +} + +#[test] +fn test_iterator_max() { + let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().cloned().max(), Some(3)); + assert_eq!(v.iter().cloned().max(), Some(10)); + assert_eq!(v[..0].iter().cloned().max(), None); + assert_eq!(v.iter().cloned().map(Mod3).max().map(|x| x.0), Some(8)); +} + +#[test] +fn test_iterator_min() { + let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().cloned().min(), Some(0)); + assert_eq!(v.iter().cloned().min(), Some(0)); + assert_eq!(v[..0].iter().cloned().min(), None); + assert_eq!(v.iter().cloned().map(Mod3).min().map(|x| x.0), Some(0)); +} + +#[test] +fn test_iterator_size_hint() { + let c = (0..).step_by(1); + let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let v2 = &[10, 11, 12]; + let vi = v.iter(); + + assert_eq!((0..).size_hint(), (usize::MAX, None)); + assert_eq!(c.size_hint(), (usize::MAX, None)); + assert_eq!(vi.clone().size_hint(), (10, Some(10))); + + assert_eq!(c.clone().take(5).size_hint(), (5, Some(5))); + assert_eq!(c.clone().skip(5).size_hint().1, None); + assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None)); + assert_eq!(c.clone().map_while(|_| None::<()>).size_hint(), (0, None)); + assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None)); + assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None)); + assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None)); + assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10))); + assert_eq!(c.clone().scan(0, |_, _| Some(0)).size_hint(), (0, None)); + assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None)); + assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None)); + assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None)); + + assert_eq!(vi.clone().take(5).size_hint(), (5, Some(5))); + assert_eq!(vi.clone().take(12).size_hint(), (10, Some(10))); + assert_eq!(vi.clone().skip(3).size_hint(), (7, Some(7))); + assert_eq!(vi.clone().skip(12).size_hint(), (0, Some(0))); + assert_eq!(vi.clone().take_while(|_| false).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().map_while(|_| None::<()>).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().skip_while(|_| false).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10))); + assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13))); + assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3))); + assert_eq!(vi.clone().scan(0, |_, _| Some(0)).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().map(|&i| i + 1).size_hint(), (10, Some(10))); + assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10))); +} + +#[test] +fn test_all() { + let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); + assert!(v.iter().all(|&x| x < 10)); + assert!(!v.iter().all(|&x| x % 2 == 0)); + assert!(!v.iter().all(|&x| x > 100)); + assert!(v[..0].iter().all(|_| panic!())); +} + +#[test] +fn test_any() { + let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); + assert!(v.iter().any(|&x| x < 10)); + assert!(v.iter().any(|&x| x % 2 == 0)); + assert!(!v.iter().any(|&x| x > 100)); + assert!(!v[..0].iter().any(|_| panic!())); +} + +#[test] +fn test_find() { + let v: &[isize] = &[1, 3, 9, 27, 103, 14, 11]; + assert_eq!(*v.iter().find(|&&x| x & 1 == 0).unwrap(), 14); + assert_eq!(*v.iter().find(|&&x| x % 3 == 0).unwrap(), 3); + assert!(v.iter().find(|&&x| x % 12 == 0).is_none()); +} + +#[test] +fn test_try_find() { + let xs: &[isize] = &[]; + assert_eq!(xs.iter().try_find(testfn), Ok(None)); + let xs: &[isize] = &[1, 2, 3, 4]; + assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2))); + let xs: &[isize] = &[1, 3, 4]; + assert_eq!(xs.iter().try_find(testfn), Err(())); + + let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; + let mut iter = xs.iter(); + assert_eq!(iter.try_find(testfn), Ok(Some(&2))); + assert_eq!(iter.try_find(testfn), Err(())); + assert_eq!(iter.next(), Some(&5)); + + fn testfn(x: &&isize) -> Result { + if **x == 2 { + return Ok(true); + } + if **x == 4 { + return Err(()); + } + Ok(false) + } +} + +#[test] +fn test_try_find_api_usability() -> Result<(), Box> { + let a = ["1", "2"]; + + let is_my_num = |s: &str, search: i32| -> Result { + Ok(s.parse::()? == search) + }; + + let val = a.iter().try_find(|&&s| is_my_num(s, 2))?; + assert_eq!(val, Some(&"2")); + + Ok(()) +} + +#[test] +fn test_position() { + let v = &[1, 3, 9, 27, 103, 14, 11]; + assert_eq!(v.iter().position(|x| *x & 1 == 0).unwrap(), 5); + assert_eq!(v.iter().position(|x| *x % 3 == 0).unwrap(), 1); + assert!(v.iter().position(|x| *x % 12 == 0).is_none()); +} + +#[test] +fn test_count() { + let xs = &[1, 2, 2, 1, 5, 9, 0, 2]; + assert_eq!(xs.iter().filter(|x| **x == 2).count(), 3); + assert_eq!(xs.iter().filter(|x| **x == 5).count(), 1); + assert_eq!(xs.iter().filter(|x| **x == 95).count(), 0); +} + +#[test] +fn test_max_by_key() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10); +} + +#[test] +fn test_max_by() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10); +} + +#[test] +fn test_min_by_key() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0); +} + +#[test] +fn test_min_by() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0); +} + +#[test] +fn test_by_ref() { + let mut xs = 0..10; + // sum the first five values + let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b); + assert_eq!(partial_sum, 10); + assert_eq!(xs.next(), Some(5)); +} + +#[test] +fn test_is_sorted() { + // Tests on integers + assert!([1, 2, 2, 9].iter().is_sorted()); + assert!(![1, 3, 2].iter().is_sorted()); + assert!([0].iter().is_sorted()); + assert!([0, 0].iter().is_sorted()); + assert!(core::iter::empty::().is_sorted()); + + // Tests on floats + assert!([1.0f32, 2.0, 2.0, 9.0].iter().is_sorted()); + assert!(![1.0f32, 3.0f32, 2.0f32].iter().is_sorted()); + assert!([0.0f32].iter().is_sorted()); + assert!([0.0f32, 0.0f32].iter().is_sorted()); + // Test cases with NaNs + assert!([f32::NAN].iter().is_sorted()); + assert!(![f32::NAN, f32::NAN].iter().is_sorted()); + assert!(![0.0, 1.0, f32::NAN].iter().is_sorted()); + // Tests from + assert!(![f32::NAN, f32::NAN, f32::NAN].iter().is_sorted()); + assert!(![1.0, f32::NAN, 2.0].iter().is_sorted()); + assert!(![2.0, f32::NAN, 1.0].iter().is_sorted()); + assert!(![2.0, f32::NAN, 1.0, 7.0].iter().is_sorted()); + assert!(![2.0, f32::NAN, 1.0, 0.0].iter().is_sorted()); + assert!(![-f32::NAN, -1.0, 0.0, 1.0, f32::NAN].iter().is_sorted()); + assert!(![f32::NAN, -f32::NAN, -1.0, 0.0, 1.0].iter().is_sorted()); + assert!(![1.0, f32::NAN, -f32::NAN, -1.0, 0.0].iter().is_sorted()); + assert!(![0.0, 1.0, f32::NAN, -f32::NAN, -1.0].iter().is_sorted()); + assert!(![-1.0, 0.0, 1.0, f32::NAN, -f32::NAN].iter().is_sorted()); + + // Tests for is_sorted_by + assert!(![6, 2, 8, 5, 1, -60, 1337].iter().is_sorted()); + assert!([6, 2, 8, 5, 1, -60, 1337].iter().is_sorted_by(|_, _| true)); + + // Tests for is_sorted_by_key + assert!([-2, -1, 0, 3].iter().is_sorted()); + assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); + assert!(!["c", "bb", "aaa"].iter().is_sorted()); + assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len())); +} + +#[test] +fn test_partition() { + fn check(xs: &mut [i32], ref p: impl Fn(&i32) -> bool, expected: usize) { + let i = xs.iter_mut().partition_in_place(p); + assert_eq!(expected, i); + assert!(xs[..i].iter().all(p)); + assert!(!xs[i..].iter().any(p)); + assert!(xs.iter().is_partitioned(p)); + if i == 0 || i == xs.len() { + assert!(xs.iter().rev().is_partitioned(p)); + } else { + assert!(!xs.iter().rev().is_partitioned(p)); + } + } + + check(&mut [], |_| true, 0); + check(&mut [], |_| false, 0); + + check(&mut [0], |_| true, 1); + check(&mut [0], |_| false, 0); + + check(&mut [-1, 1], |&x| x > 0, 1); + check(&mut [-1, 1], |&x| x < 0, 1); + + let ref mut xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + check(xs, |_| true, 10); + check(xs, |_| false, 0); + check(xs, |&x| x % 2 == 0, 5); // evens + check(xs, |&x| x % 2 == 1, 5); // odds + check(xs, |&x| x % 3 == 0, 4); // multiple of 3 + check(xs, |&x| x % 4 == 0, 3); // multiple of 4 + check(xs, |&x| x % 5 == 0, 2); // multiple of 5 + check(xs, |&x| x < 3, 3); // small + check(xs, |&x| x > 6, 3); // large +} + +#[test] +fn test_iterator_rev_advance_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter().rev(); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]); + assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap())); + } + + assert_eq!(v.iter().rev().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_by(100), Err(NonZero::new(100 - v.len()).unwrap())); +} + +#[test] +fn test_find_map() { + let xs: &[isize] = &[]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[3, 5]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[4, 5]; + assert_eq!(xs.iter().find_map(half_if_even), Some(2)); + let xs: &[isize] = &[3, 6]; + assert_eq!(xs.iter().find_map(half_if_even), Some(3)); + + let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; + let mut iter = xs.iter(); + assert_eq!(iter.find_map(half_if_even), Some(1)); + assert_eq!(iter.find_map(half_if_even), Some(2)); + assert_eq!(iter.find_map(half_if_even), Some(3)); + assert_eq!(iter.next(), Some(&7)); + + fn half_if_even(x: &isize) -> Option { + if x % 2 == 0 { Some(x / 2) } else { None } + } +} + +#[test] +fn test_try_reduce() { + let v = [1usize, 2, 3, 4, 5]; + let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y)); + assert_eq!(sum, Some(Some(15))); + + let v = [1, 2, 3, 4, 5, usize::MAX]; + let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y)); + assert_eq!(sum, None); + + let v: [usize; 0] = []; + let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y)); + assert_eq!(sum, Some(None)); + + let v = ["1", "2", "3", "4", "5"]; + let max = v.into_iter().try_reduce(|x, y| { + if x.parse::().ok()? > y.parse::().ok()? { Some(x) } else { Some(y) } + }); + assert_eq!(max, Some(Some("5"))); + + let v = ["1", "2", "3", "4", "5"]; + let max: Result, ::Err> = + v.into_iter().try_reduce(|x, y| { + if x.parse::()? > y.parse::()? { Ok(x) } else { Ok(y) } + }); + assert_eq!(max, Ok(Some("5"))); +} + +#[test] +fn test_iterator_len() { + let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(v[..4].iter().count(), 4); + assert_eq!(v[..10].iter().count(), 10); + assert_eq!(v[..0].iter().count(), 0); +} + +#[test] +fn test_collect() { + let a = vec![1, 2, 3, 4, 5]; + let b: Vec = a.iter().cloned().collect(); + assert!(a == b); +} + +#[test] +fn test_try_collect() { + use core::ops::ControlFlow::{Break, Continue}; + + let u = vec![Some(1), Some(2), Some(3)]; + let v = u.into_iter().try_collect::>(); + assert_eq!(v, Some(vec![1, 2, 3])); + + let u = vec![Some(1), Some(2), None, Some(3)]; + let mut it = u.into_iter(); + let v = it.try_collect::>(); + assert_eq!(v, None); + let v = it.try_collect::>(); + assert_eq!(v, Some(vec![3])); + + let u: Vec> = vec![Ok(1), Ok(2), Ok(3)]; + let v = u.into_iter().try_collect::>(); + assert_eq!(v, Ok(vec![1, 2, 3])); + + let u = vec![Ok(1), Ok(2), Err(()), Ok(3)]; + let v = u.into_iter().try_collect::>(); + assert_eq!(v, Err(())); + + let numbers = vec![1, 2, 3, 4, 5]; + let all_positive = numbers + .iter() + .cloned() + .map(|n| if n > 0 { Some(n) } else { None }) + .try_collect::>(); + assert_eq!(all_positive, Some(numbers)); + + let numbers = vec![-2, -1, 0, 1, 2]; + let all_positive = + numbers.into_iter().map(|n| if n > 0 { Some(n) } else { None }).try_collect::>(); + assert_eq!(all_positive, None); + + let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)]; + let mut it = u.into_iter(); + + let v = it.try_collect::>(); + assert_eq!(v, Break(3)); + + let v = it.try_collect::>(); + assert_eq!(v, Continue(vec![4, 5])); +} + +#[test] +fn test_collect_into() { + let a = vec![1, 2, 3, 4, 5]; + let mut b = Vec::new(); + a.iter().cloned().collect_into(&mut b); + assert!(a == b); +} + +#[test] +fn iter_try_collect_uses_try_fold_not_next() { + // This makes sure it picks up optimizations, and doesn't use the `&mut I` impl. + struct PanicOnNext(I); + impl Iterator for PanicOnNext { + type Item = I::Item; + fn next(&mut self) -> Option { + panic!("Iterator::next should not be called!") + } + fn try_fold(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: std::ops::Try, + { + self.0.try_fold(init, f) + } + } + + let it = (0..10).map(Some); + let _ = PanicOnNext(it).try_collect::>(); + // validation is just that it didn't panic. +} + +#[test] +fn test_next_chunk() { + let mut it = 0..12; + assert_eq!(it.next_chunk().unwrap(), [0, 1, 2, 3]); + assert_eq!(it.next_chunk().unwrap(), []); + assert_eq!(it.next_chunk().unwrap(), [4, 5, 6, 7, 8, 9]); + assert_eq!(it.next_chunk::<4>().unwrap_err().as_slice(), &[10, 11]); + + let mut it = std::iter::repeat_with(|| panic!()); + assert_eq!(it.next_chunk::<0>().unwrap(), []); +} + +#[test] +fn test_collect_into_tuples() { + let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)]; + let b = vec![1, 4, 7]; + let c = vec![2, 5, 8]; + let d = vec![3, 6, 9]; + let mut e = (Vec::new(), Vec::new(), Vec::new()); + a.iter().cloned().collect_into(&mut e); + assert!(e.0 == b); + assert!(e.1 == c); + assert!(e.2 == d); +} + +#[test] +fn test_collect_for_tuples() { + let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)]; + let b = vec![1, 4, 7]; + let c = vec![2, 5, 8]; + let d = vec![3, 6, 9]; + let e: (Vec<_>, Vec<_>, Vec<_>) = a.into_iter().collect(); + assert!(e.0 == b); + assert!(e.1 == c); + assert!(e.2 == d); +} + +// just tests by whether or not this compiles +fn _empty_impl_all_auto_traits() { + use std::panic::{RefUnwindSafe, UnwindSafe}; + fn all_auto_traits() {} + + all_auto_traits::>(); +} diff --git a/library/coretests/tests/iter/traits/mod.rs b/library/coretests/tests/iter/traits/mod.rs new file mode 100644 index 00000000000..80619f53f25 --- /dev/null +++ b/library/coretests/tests/iter/traits/mod.rs @@ -0,0 +1,4 @@ +mod accum; +mod double_ended; +mod iterator; +mod step; diff --git a/library/coretests/tests/iter/traits/step.rs b/library/coretests/tests/iter/traits/step.rs new file mode 100644 index 00000000000..bf935af397c --- /dev/null +++ b/library/coretests/tests/iter/traits/step.rs @@ -0,0 +1,100 @@ +use core::iter::*; + +#[test] +fn test_steps_between() { + assert_eq!(Step::steps_between(&20_u8, &200_u8), (180_usize, Some(180_usize))); + assert_eq!(Step::steps_between(&-20_i8, &80_i8), (100_usize, Some(100_usize))); + assert_eq!(Step::steps_between(&-120_i8, &80_i8), (200_usize, Some(200_usize))); + assert_eq!( + Step::steps_between(&20_u32, &4_000_100_u32), + (4_000_080_usize, Some(4_000_080_usize)) + ); + assert_eq!(Step::steps_between(&-20_i32, &80_i32), (100_usize, Some(100_usize))); + assert_eq!( + Step::steps_between(&-2_000_030_i32, &2_000_050_i32), + (4_000_080_usize, Some(4_000_080_usize)) + ); + + // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms + + assert_eq!(Step::steps_between(&20_u128, &200_u128), (180_usize, Some(180_usize))); + assert_eq!(Step::steps_between(&-20_i128, &80_i128), (100_usize, Some(100_usize))); + if cfg!(target_pointer_width = "64") { + assert_eq!( + Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), + (usize::MAX, Some(usize::MAX)) + ); + } + assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), (usize::MAX, None)); + assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), (usize::MAX, None)); + assert_eq!( + Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,), + (usize::MAX, None), + ); + + assert_eq!(Step::steps_between(&100_u32, &10_u32), (0, None)); +} + +#[test] +fn test_step_forward() { + assert_eq!(Step::forward_checked(55_u8, 200_usize), Some(255_u8)); + assert_eq!(Step::forward_checked(252_u8, 200_usize), None); + assert_eq!(Step::forward_checked(0_u8, 256_usize), None); + assert_eq!(Step::forward_checked(-110_i8, 200_usize), Some(90_i8)); + assert_eq!(Step::forward_checked(-110_i8, 248_usize), None); + assert_eq!(Step::forward_checked(-126_i8, 256_usize), None); + + assert_eq!(Step::forward_checked(35_u16, 100_usize), Some(135_u16)); + assert_eq!(Step::forward_checked(35_u16, 65500_usize), Some(u16::MAX)); + assert_eq!(Step::forward_checked(36_u16, 65500_usize), None); + assert_eq!(Step::forward_checked(-110_i16, 200_usize), Some(90_i16)); + assert_eq!(Step::forward_checked(-20_030_i16, 50_050_usize), Some(30_020_i16)); + assert_eq!(Step::forward_checked(-10_i16, 40_000_usize), None); + assert_eq!(Step::forward_checked(-10_i16, 70_000_usize), None); + + assert_eq!(Step::forward_checked(10_u128, 70_000_usize), Some(70_010_u128)); + assert_eq!(Step::forward_checked(10_i128, 70_030_usize), Some(70_040_i128)); + assert_eq!( + Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0xff_usize), + Some(u128::MAX), + ); + assert_eq!( + Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0x100_usize), + None + ); + assert_eq!( + Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0xff_usize), + Some(i128::MAX), + ); + assert_eq!( + Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize), + None + ); +} + +#[test] +fn test_step_backward() { + assert_eq!(Step::backward_checked(255_u8, 200_usize), Some(55_u8)); + assert_eq!(Step::backward_checked(100_u8, 200_usize), None); + assert_eq!(Step::backward_checked(255_u8, 256_usize), None); + assert_eq!(Step::backward_checked(90_i8, 200_usize), Some(-110_i8)); + assert_eq!(Step::backward_checked(110_i8, 248_usize), None); + assert_eq!(Step::backward_checked(127_i8, 256_usize), None); + + assert_eq!(Step::backward_checked(135_u16, 100_usize), Some(35_u16)); + assert_eq!(Step::backward_checked(u16::MAX, 65500_usize), Some(35_u16)); + assert_eq!(Step::backward_checked(10_u16, 11_usize), None); + assert_eq!(Step::backward_checked(90_i16, 200_usize), Some(-110_i16)); + assert_eq!(Step::backward_checked(30_020_i16, 50_050_usize), Some(-20_030_i16)); + assert_eq!(Step::backward_checked(-10_i16, 40_000_usize), None); + assert_eq!(Step::backward_checked(-10_i16, 70_000_usize), None); + + assert_eq!(Step::backward_checked(70_010_u128, 70_000_usize), Some(10_u128)); + assert_eq!(Step::backward_checked(70_020_i128, 70_030_usize), Some(-10_i128)); + assert_eq!(Step::backward_checked(10_u128, 7_usize), Some(3_u128)); + assert_eq!(Step::backward_checked(10_u128, 11_usize), None); + assert_eq!( + Step::backward_checked(-0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize), + Some(i128::MIN) + ); +} diff --git a/library/coretests/tests/lazy.rs b/library/coretests/tests/lazy.rs new file mode 100644 index 00000000000..32d0ac51f03 --- /dev/null +++ b/library/coretests/tests/lazy.rs @@ -0,0 +1,167 @@ +use core::cell::{Cell, LazyCell, OnceCell}; +use core::sync::atomic::AtomicUsize; +use core::sync::atomic::Ordering::SeqCst; + +#[test] +fn once_cell() { + let c = OnceCell::new(); + assert!(c.get().is_none()); + c.get_or_init(|| 92); + assert_eq!(c.get(), Some(&92)); + + c.get_or_init(|| panic!("Kaboom!")); + assert_eq!(c.get(), Some(&92)); +} + +#[test] +fn once_cell_get_mut() { + let mut c = OnceCell::new(); + assert!(c.get_mut().is_none()); + c.set(90).unwrap(); + *c.get_mut().unwrap() += 2; + assert_eq!(c.get_mut(), Some(&mut 92)); +} + +#[test] +fn once_cell_drop() { + static DROP_CNT: AtomicUsize = AtomicUsize::new(0); + struct Dropper; + impl Drop for Dropper { + fn drop(&mut self) { + DROP_CNT.fetch_add(1, SeqCst); + } + } + + let x = OnceCell::new(); + x.get_or_init(|| Dropper); + assert_eq!(DROP_CNT.load(SeqCst), 0); + drop(x); + assert_eq!(DROP_CNT.load(SeqCst), 1); +} + +#[test] +fn unsync_once_cell_drop_empty() { + let x = OnceCell::<&'static str>::new(); + drop(x); +} + +/* FIXME(#110395) +#[test] +const fn once_cell_const() { + let _once_cell: OnceCell = OnceCell::new(); + let _once_cell: OnceCell = OnceCell::from(32); +} +*/ + +#[test] +fn clone() { + let s = OnceCell::new(); + let c = s.clone(); + assert!(c.get().is_none()); + + s.set("hello").unwrap(); + let c = s.clone(); + assert_eq!(c.get().map(|c| *c), Some("hello")); +} + +#[test] +fn from_impl() { + assert_eq!(OnceCell::from("value").get(), Some(&"value")); + assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); +} + +#[test] +fn partialeq_impl() { + assert!(OnceCell::from("value") == OnceCell::from("value")); + assert!(OnceCell::from("foo") != OnceCell::from("bar")); + + assert!(OnceCell::<&'static str>::new() == OnceCell::new()); + assert!(OnceCell::<&'static str>::new() != OnceCell::from("value")); +} + +#[test] +fn into_inner() { + let cell: OnceCell<&'static str> = OnceCell::new(); + assert_eq!(cell.into_inner(), None); + let cell = OnceCell::new(); + cell.set("hello").unwrap(); + assert_eq!(cell.into_inner(), Some("hello")); +} + +#[test] +fn lazy_new() { + let called = Cell::new(0); + let x = LazyCell::new(|| { + called.set(called.get() + 1); + 92 + }); + + assert_eq!(called.get(), 0); + + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.get(), 1); + + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.get(), 1); +} + +// Check that we can infer `T` from closure's type. +#[test] +fn lazy_type_inference() { + let _ = LazyCell::new(|| ()); +} + +#[test] +#[cfg(panic = "unwind")] +#[should_panic = "LazyCell instance has previously been poisoned"] +fn lazy_force_mut_panic() { + let mut lazy = LazyCell::::new(|| panic!()); + std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + let _ = LazyCell::force_mut(&mut lazy); + })) + .unwrap_err(); + let _ = &*lazy; +} + +#[test] +fn lazy_force_mut() { + let s = "abc".to_owned(); + let mut lazy = LazyCell::new(move || s); + LazyCell::force_mut(&mut lazy); + let p = LazyCell::force_mut(&mut lazy); + p.clear(); + LazyCell::force_mut(&mut lazy); +} + +#[test] +fn aliasing_in_get() { + let x = OnceCell::new(); + x.set(42).unwrap(); + let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option` --+ + let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option` | + println!("{at_x}"); // <------- up until here ---------------------------+ +} + +#[test] +#[should_panic(expected = "reentrant init")] +fn reentrant_init() { + let x: OnceCell> = OnceCell::new(); + let dangling_ref: Cell> = Cell::new(None); + x.get_or_init(|| { + let r = x.get_or_init(|| Box::new(92)); + dangling_ref.set(Some(r)); + Box::new(62) + }); + eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); +} + +#[test] +fn dropck() { + let cell = OnceCell::new(); + { + let s = String::new(); + cell.set(&s).unwrap(); + } +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs new file mode 100644 index 00000000000..a8980c5f30a --- /dev/null +++ b/library/coretests/tests/lib.rs @@ -0,0 +1,194 @@ +// tidy-alphabetical-start +#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] +#![cfg_attr(test, feature(cfg_match))] +#![feature(alloc_layout_extra)] +#![feature(array_chunks)] +#![feature(array_ptr_get)] +#![feature(array_try_from_fn)] +#![feature(array_windows)] +#![feature(ascii_char)] +#![feature(ascii_char_variants)] +#![feature(async_iter_from_iter)] +#![feature(async_iterator)] +#![feature(bigint_helper_methods)] +#![feature(cell_update)] +#![feature(clone_to_uninit)] +#![feature(const_black_box)] +#![feature(const_eval_select)] +#![feature(const_swap_nonoverlapping)] +#![feature(const_trait_impl)] +#![feature(core_intrinsics)] +#![feature(core_intrinsics_fallbacks)] +#![feature(core_io_borrowed_buf)] +#![feature(core_private_bignum)] +#![feature(core_private_diy_float)] +#![feature(dec2flt)] +#![feature(duration_constants)] +#![feature(duration_constructors)] +#![feature(error_generic_member_access)] +#![feature(exact_size_is_empty)] +#![feature(extern_types)] +#![feature(float_minimum_maximum)] +#![feature(flt2dec)] +#![feature(fmt_internals)] +#![feature(formatting_options)] +#![feature(freeze)] +#![feature(future_join)] +#![feature(generic_assert_internals)] +#![feature(get_many_mut)] +#![feature(hasher_prefixfree_extras)] +#![feature(hashmap_internals)] +#![feature(inline_const_pat)] +#![feature(int_roundings)] +#![feature(ip)] +#![feature(ip_from)] +#![feature(is_ascii_octdigit)] +#![feature(iter_advance_by)] +#![feature(iter_array_chunks)] +#![feature(iter_chain)] +#![feature(iter_collect_into)] +#![feature(iter_intersperse)] +#![feature(iter_is_partitioned)] +#![feature(iter_map_windows)] +#![feature(iter_next_chunk)] +#![feature(iter_order_by)] +#![feature(iter_partition_in_place)] +#![feature(iterator_try_collect)] +#![feature(iterator_try_reduce)] +#![feature(layout_for_ptr)] +#![feature(lazy_get)] +#![feature(maybe_uninit_fill)] +#![feature(maybe_uninit_uninit_array_transpose)] +#![feature(maybe_uninit_write_slice)] +#![feature(min_specialization)] +#![feature(never_type)] +#![feature(num_midpoint_signed)] +#![feature(numfmt)] +#![feature(pattern)] +#![feature(pointer_is_aligned_to)] +#![feature(portable_simd)] +#![feature(ptr_metadata)] +#![feature(slice_from_ptr_range)] +#![feature(slice_internals)] +#![feature(slice_partition_dedup)] +#![feature(slice_split_once)] +#![feature(slice_take)] +#![feature(split_array)] +#![feature(split_as_slice)] +#![feature(std_internals)] +#![feature(step_trait)] +#![feature(str_internals)] +#![feature(strict_provenance_atomic_ptr)] +#![feature(strict_provenance_lints)] +#![feature(test)] +#![feature(trait_upcasting)] +#![feature(trusted_len)] +#![feature(trusted_random_access)] +#![feature(try_blocks)] +#![feature(try_find)] +#![feature(try_trait_v2)] +#![feature(unsigned_is_multiple_of)] +#![feature(unsize)] +#![feature(unsized_tuple_coercion)] +#![feature(unwrap_infallible)] +// tidy-alphabetical-end +#![allow(internal_features)] +#![deny(fuzzy_provenance_casts)] +#![deny(unsafe_op_in_unsafe_fn)] + +/// Version of `assert_matches` that ignores fancy runtime printing in const context and uses structural equality. +macro_rules! assert_eq_const_safe { + ($left:expr, $right:expr) => { + assert_eq_const_safe!($left, $right, concat!(stringify!($left), " == ", stringify!($right))); + }; + ($left:expr, $right:expr$(, $($arg:tt)+)?) => { + { + fn runtime() { + assert_eq!($left, $right, $($($arg)*),*); + } + const fn compiletime() { + assert!(matches!($left, const { $right })); + } + core::intrinsics::const_eval_select((), compiletime, runtime) + } + }; +} + +/// Creates a test for runtime and a test for constant-time. +macro_rules! test_runtime_and_compiletime { + ($( + $(#[$attr:meta])* + fn $test:ident() $block:block + )*) => { + $( + $(#[$attr])* + #[test] + fn $test() $block + $(#[$attr])* + const _: () = $block; + )* + } +} + +mod alloc; +mod any; +mod array; +mod ascii; +mod ascii_char; +mod asserting; +mod async_iter; +mod atomic; +mod bool; +mod cell; +mod char; +mod clone; +mod cmp; +mod const_ptr; +mod convert; +mod ffi; +mod fmt; +mod future; +mod hash; +mod intrinsics; +mod io; +mod iter; +mod lazy; +#[cfg(not(bootstrap))] +mod macros; +#[cfg(bootstrap)] +mod macros_bootstrap; +mod manually_drop; +mod mem; +mod net; +mod nonzero; +mod num; +mod ops; +mod option; +mod panic; +mod pattern; +mod pin; +mod pin_macro; +mod ptr; +mod result; +mod simd; +mod slice; +mod str; +mod str_lossy; +mod task; +mod time; +mod tuple; +mod unicode; +mod waker; + +/// Copied from `std::test_helpers::test_rng`, see that function for rationale. +#[track_caller] +#[allow(dead_code)] // Not used in all configurations. +pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { + use core::hash::{BuildHasher, Hash, Hasher}; + let mut hasher = std::hash::RandomState::new().build_hasher(); + core::panic::Location::caller().hash(&mut hasher); + let hc64 = hasher.finish(); + let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); + let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); + rand::SeedableRng::from_seed(seed) +} diff --git a/library/coretests/tests/macros.rs b/library/coretests/tests/macros.rs new file mode 100644 index 00000000000..b30a40b7df2 --- /dev/null +++ b/library/coretests/tests/macros.rs @@ -0,0 +1,206 @@ +#![allow(unused_must_use)] + +#[allow(dead_code)] +trait Trait { + fn blah(&self); +} + +#[allow(dead_code)] +struct Struct; + +impl Trait for Struct { + cfg_match! { + feature = "blah" => { + fn blah(&self) { + unimplemented!(); + } + } + _ => { + fn blah(&self) { + unimplemented!(); + } + } + } +} + +#[test] +fn assert_eq_trailing_comma() { + assert_eq!(1, 1,); +} + +#[test] +fn assert_escape() { + assert!(r#"☃\backslash"#.contains("\\")); +} + +#[test] +fn assert_ne_trailing_comma() { + assert_ne!(1, 2,); +} + +#[rustfmt::skip] +#[test] +fn matches_leading_pipe() { + matches!(1, | 1 | 2 | 3); +} + +#[test] +fn cfg_match_basic() { + cfg_match! { + target_pointer_width = "64" => { fn f0_() -> bool { true }} + } + + cfg_match! { + unix => { fn f1_() -> bool { true } } + any(target_os = "macos", target_os = "linux") => { fn f1_() -> bool { false }} + } + + cfg_match! { + target_pointer_width = "32" => { fn f2_() -> bool { false } } + target_pointer_width = "64" => { fn f2_() -> bool { true } } + } + + cfg_match! { + target_pointer_width = "16" => { fn f3_() -> i32 { 1 } } + _ => { fn f3_() -> i32 { 2 }} + } + + #[cfg(target_pointer_width = "64")] + assert!(f0_()); + + #[cfg(unix)] + assert!(f1_()); + + #[cfg(target_pointer_width = "32")] + assert!(!f2_()); + #[cfg(target_pointer_width = "64")] + assert!(f2_()); + + #[cfg(not(target_pointer_width = "16"))] + assert_eq!(f3_(), 2); +} + +#[test] +fn cfg_match_debug_assertions() { + cfg_match! { + debug_assertions => { + assert!(cfg!(debug_assertions)); + assert_eq!(4, 2+2); + } + _ => { + assert!(cfg!(not(debug_assertions))); + assert_eq!(10, 5+5); + } + } +} + +#[cfg(target_pointer_width = "64")] +#[test] +fn cfg_match_no_duplication_on_64() { + cfg_match! { + windows => { + fn foo() {} + } + unix => { + fn foo() {} + } + target_pointer_width = "64" => { + fn foo() {} + } + } + foo(); +} + +#[test] +fn cfg_match_options() { + cfg_match! { + test => { + use core::option::Option as Option2; + fn works1() -> Option2 { Some(1) } + } + _ => { fn works1() -> Option { None } } + } + + cfg_match! { + feature = "foo" => { fn works2() -> bool { false } } + test => { fn works2() -> bool { true } } + _ => { fn works2() -> bool { false } } + } + + cfg_match! { + feature = "foo" => { fn works3() -> bool { false } } + _ => { fn works3() -> bool { true } } + } + + cfg_match! { + test => { + use core::option::Option as Option3; + fn works4() -> Option3 { Some(1) } + } + } + + cfg_match! { + feature = "foo" => { fn works5() -> bool { false } } + test => { fn works5() -> bool { true } } + } + + assert!(works1().is_some()); + assert!(works2()); + assert!(works3()); + assert!(works4().is_some()); + assert!(works5()); +} + +#[test] +fn cfg_match_two_functions() { + cfg_match! { + target_pointer_width = "64" => { + fn foo1() {} + fn bar1() {} + } + _ => { + fn foo2() {} + fn bar2() {} + } + } + + #[cfg(target_pointer_width = "64")] + { + foo1(); + bar1(); + } + #[cfg(not(target_pointer_width = "64"))] + { + foo2(); + bar2(); + } +} + +fn _accepts_expressions() -> i32 { + cfg_match! { + unix => { 1 } + _ => { 2 } + } +} + +// The current implementation expands to a macro call, which allows the use of expression +// statements. +fn _allows_stmt_expr_attributes() { + let one = 1; + let two = 2; + cfg_match! { + unix => { one * two; } + _ => { one + two; } + } +} + +fn _expression() { + let _ = cfg_match!({ + windows => { + " XP" + } + _ => { + "" + } + }); +} diff --git a/library/coretests/tests/macros_bootstrap.rs b/library/coretests/tests/macros_bootstrap.rs new file mode 100644 index 00000000000..f10ef862c5d --- /dev/null +++ b/library/coretests/tests/macros_bootstrap.rs @@ -0,0 +1,193 @@ +#![allow(unused_must_use)] + +#[allow(dead_code)] +trait Trait { + fn blah(&self); +} + +#[allow(dead_code)] +struct Struct; + +impl Trait for Struct { + cfg_match! { + cfg(feature = "blah") => { + fn blah(&self) { + unimplemented!(); + } + } + _ => { + fn blah(&self) { + unimplemented!(); + } + } + } +} + +#[test] +fn assert_eq_trailing_comma() { + assert_eq!(1, 1,); +} + +#[test] +fn assert_escape() { + assert!(r#"☃\backslash"#.contains("\\")); +} + +#[test] +fn assert_ne_trailing_comma() { + assert_ne!(1, 2,); +} + +#[rustfmt::skip] +#[test] +fn matches_leading_pipe() { + matches!(1, | 1 | 2 | 3); +} + +#[test] +fn cfg_match_basic() { + cfg_match! { + cfg(target_pointer_width = "64") => { fn f0_() -> bool { true }} + } + + cfg_match! { + cfg(unix) => { fn f1_() -> bool { true }} + cfg(any(target_os = "macos", target_os = "linux")) => { fn f1_() -> bool { false }} + } + + cfg_match! { + cfg(target_pointer_width = "32") => { fn f2_() -> bool { false }} + cfg(target_pointer_width = "64") => { fn f2_() -> bool { true }} + } + + cfg_match! { + cfg(target_pointer_width = "16") => { fn f3_() -> i32 { 1 }} + _ => { fn f3_() -> i32 { 2 }} + } + + #[cfg(target_pointer_width = "64")] + assert!(f0_()); + + #[cfg(unix)] + assert!(f1_()); + + #[cfg(target_pointer_width = "32")] + assert!(!f2_()); + #[cfg(target_pointer_width = "64")] + assert!(f2_()); + + #[cfg(not(target_pointer_width = "16"))] + assert_eq!(f3_(), 2); +} + +#[test] +fn cfg_match_debug_assertions() { + cfg_match! { + cfg(debug_assertions) => { + assert!(cfg!(debug_assertions)); + assert_eq!(4, 2+2); + } + _ => { + assert!(cfg!(not(debug_assertions))); + assert_eq!(10, 5+5); + } + } +} + +#[cfg(target_pointer_width = "64")] +#[test] +fn cfg_match_no_duplication_on_64() { + cfg_match! { + cfg(windows) => { + fn foo() {} + } + cfg(unix) => { + fn foo() {} + } + cfg(target_pointer_width = "64") => { + fn foo() {} + } + } + foo(); +} + +#[test] +fn cfg_match_options() { + cfg_match! { + cfg(test) => { + use core::option::Option as Option2; + fn works1() -> Option2 { Some(1) } + } + _ => { fn works1() -> Option { None } } + } + + cfg_match! { + cfg(feature = "foo") => { fn works2() -> bool { false } } + cfg(test) => { fn works2() -> bool { true } } + _ => { fn works2() -> bool { false } } + } + + cfg_match! { + cfg(feature = "foo") => { fn works3() -> bool { false } } + _ => { fn works3() -> bool { true } } + } + + cfg_match! { + cfg(test) => { + use core::option::Option as Option3; + fn works4() -> Option3 { Some(1) } + } + } + + cfg_match! { + cfg(feature = "foo") => { fn works5() -> bool { false } } + cfg(test) => { fn works5() -> bool { true } } + } + + assert!(works1().is_some()); + assert!(works2()); + assert!(works3()); + assert!(works4().is_some()); + assert!(works5()); +} + +#[test] +fn cfg_match_two_functions() { + cfg_match! { + cfg(target_pointer_width = "64") => { + fn foo1() {} + fn bar1() {} + } + _ => { + fn foo2() {} + fn bar2() {} + } + } + + #[cfg(target_pointer_width = "64")] + { + foo1(); + bar1(); + } + #[cfg(not(target_pointer_width = "64"))] + { + foo2(); + bar2(); + } +} + +fn _accepts_expressions() -> i32 { + cfg_match! { + cfg(unix) => { 1 } + _ => { 2 } + } +} + +fn _allows_stmt_expr_attributes() { + let one = 1; + let two = 2; + cfg_match! { + cfg(unix) => { one * two; } + _ => { one + two; } + } +} diff --git a/library/coretests/tests/manually_drop.rs b/library/coretests/tests/manually_drop.rs new file mode 100644 index 00000000000..bbf444471ad --- /dev/null +++ b/library/coretests/tests/manually_drop.rs @@ -0,0 +1,29 @@ +#![allow(undropped_manually_drops)] + +use core::mem::ManuallyDrop; + +#[test] +fn smoke() { + #[derive(Clone)] + struct TypeWithDrop; + impl Drop for TypeWithDrop { + fn drop(&mut self) { + unreachable!("Should not get dropped"); + } + } + + let x = ManuallyDrop::new(TypeWithDrop); + drop(x); + + // also test unsizing + let x: Box> = + Box::new(ManuallyDrop::new([TypeWithDrop, TypeWithDrop])); + drop(x); + + // test clone and clone_from implementations + let mut x = ManuallyDrop::new(TypeWithDrop); + let y = x.clone(); + x.clone_from(&y); + drop(x); + drop(y); +} diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs new file mode 100644 index 00000000000..1b5c5fc82a6 --- /dev/null +++ b/library/coretests/tests/mem.rs @@ -0,0 +1,797 @@ +use core::mem::*; +use core::ptr; +#[cfg(panic = "unwind")] +use std::rc::Rc; + +#[test] +fn size_of_basic() { + assert_eq!(size_of::(), 1); + assert_eq!(size_of::(), 2); + assert_eq!(size_of::(), 4); + assert_eq!(size_of::(), 8); +} + +#[test] +#[cfg(target_pointer_width = "16")] +fn size_of_16() { + assert_eq!(size_of::(), 2); + assert_eq!(size_of::<*const usize>(), 2); +} + +#[test] +#[cfg(target_pointer_width = "32")] +fn size_of_32() { + assert_eq!(size_of::(), 4); + assert_eq!(size_of::<*const usize>(), 4); +} + +#[test] +#[cfg(target_pointer_width = "64")] +fn size_of_64() { + assert_eq!(size_of::(), 8); + assert_eq!(size_of::<*const usize>(), 8); +} + +#[test] +fn size_of_val_basic() { + assert_eq!(size_of_val(&1u8), 1); + assert_eq!(size_of_val(&1u16), 2); + assert_eq!(size_of_val(&1u32), 4); + assert_eq!(size_of_val(&1u64), 8); +} + +#[test] +fn align_of_basic() { + assert_eq!(align_of::(), 1); + assert_eq!(align_of::(), 2); + assert_eq!(align_of::(), 4); +} + +#[test] +#[cfg(target_pointer_width = "16")] +fn align_of_16() { + assert_eq!(align_of::(), 2); + assert_eq!(align_of::<*const usize>(), 2); +} + +#[test] +#[cfg(target_pointer_width = "32")] +fn align_of_32() { + assert_eq!(align_of::(), 4); + assert_eq!(align_of::<*const usize>(), 4); +} + +#[test] +#[cfg(target_pointer_width = "64")] +fn align_of_64() { + assert_eq!(align_of::(), 8); + assert_eq!(align_of::<*const usize>(), 8); +} + +#[test] +fn align_of_val_basic() { + assert_eq!(align_of_val(&1u8), 1); + assert_eq!(align_of_val(&1u16), 2); + assert_eq!(align_of_val(&1u32), 4); +} + +#[test] +fn align_of_val_raw_packed() { + #[repr(C, packed)] + struct B { + f: [u32], + } + let storage = [0u8; 4]; + let b: *const B = ptr::from_raw_parts(storage.as_ptr(), 1); + assert_eq!(unsafe { align_of_val_raw(b) }, 1); + + const ALIGN_OF_VAL_RAW: usize = { + let storage = [0u8; 4]; + let b: *const B = ptr::from_raw_parts(storage.as_ptr(), 1); + unsafe { align_of_val_raw(b) } + }; + assert_eq!(ALIGN_OF_VAL_RAW, 1); +} + +#[test] +fn test_swap() { + let mut x = 31337; + let mut y = 42; + swap(&mut x, &mut y); + assert_eq!(x, 42); + assert_eq!(y, 31337); +} + +#[test] +fn test_replace() { + let mut x = Some("test".to_string()); + let y = replace(&mut x, None); + assert!(x.is_none()); + assert!(y.is_some()); +} + +#[test] +fn test_transmute_copy() { + assert_eq!(1, unsafe { transmute_copy(&1) }); +} + +#[test] +fn test_transmute_copy_shrink() { + assert_eq!(0_u8, unsafe { transmute_copy(&0_u64) }); +} + +#[test] +fn test_transmute_copy_unaligned() { + #[repr(C)] + #[derive(Default)] + struct Unaligned { + a: u8, + b: [u8; 8], + } + + let u = Unaligned::default(); + assert_eq!(0_u64, unsafe { transmute_copy(&u.b) }); +} + +#[test] +#[cfg(panic = "unwind")] +fn test_transmute_copy_grow_panics() { + use std::panic; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { + let _unused: u64 = transmute_copy(&1_u8); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| { + if *s == "cannot transmute_copy if Dst is larger than Src" { + Ok(s) + } else { + Err(s) + } + }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + } + } +} + +#[test] +#[allow(dead_code)] +fn test_discriminant_send_sync() { + enum Regular { + A, + B(i32), + } + enum NotSendSync { + A(*const i32), + } + + fn is_send_sync() {} + + is_send_sync::>(); + is_send_sync::>(); +} + +#[test] +fn assume_init_good() { + const TRUE: bool = unsafe { MaybeUninit::::new(true).assume_init() }; + + assert!(TRUE); +} + +#[test] +fn uninit_array_assume_init() { + let mut array = [MaybeUninit::::uninit(); 5]; + array[0].write(3); + array[1].write(1); + array[2].write(4); + array[3].write(1); + array[4].write(5); + + let array = unsafe { array.transpose().assume_init() }; + + assert_eq!(array, [3, 1, 4, 1, 5]); + + let [] = unsafe { [MaybeUninit::::uninit(); 0].transpose().assume_init() }; +} + +#[test] +fn uninit_write_copy_of_slice() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 64]; + + assert_eq!(dst.write_copy_of_slice(&src), &src); +} + +#[test] +#[should_panic(expected = "source slice length (32) does not match destination slice length (64)")] +fn uninit_write_copy_of_slice_panic_lt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 32]; + + dst.write_copy_of_slice(&src); +} + +#[test] +#[should_panic(expected = "source slice length (128) does not match destination slice length (64)")] +fn uninit_write_copy_of_slice_panic_gt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 128]; + + dst.write_copy_of_slice(&src); +} + +#[test] +fn uninit_write_clone_of_slice() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 64]; + + assert_eq!(dst.write_clone_of_slice(&src), &src); +} + +#[test] +#[should_panic(expected = "destination and source slices have different lengths")] +fn uninit_write_clone_of_slice_panic_lt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 32]; + + dst.write_clone_of_slice(&src); +} + +#[test] +#[should_panic(expected = "destination and source slices have different lengths")] +fn uninit_write_clone_of_slice_panic_gt() { + let mut dst = [MaybeUninit::uninit(); 64]; + let src = [0; 128]; + + dst.write_clone_of_slice(&src); +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_write_clone_of_slice_mid_panic() { + use std::panic; + + enum IncrementOrPanic { + Increment(Rc<()>), + ExpectedPanic, + UnexpectedPanic, + } + + impl Clone for IncrementOrPanic { + fn clone(&self) -> Self { + match self { + Self::Increment(rc) => Self::Increment(rc.clone()), + Self::ExpectedPanic => panic!("expected panic on clone"), + Self::UnexpectedPanic => panic!("unexpected panic on clone"), + } + } + } + + let rc = Rc::new(()); + + let mut dst = [ + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + ]; + + let src = [ + IncrementOrPanic::Increment(rc.clone()), + IncrementOrPanic::Increment(rc.clone()), + IncrementOrPanic::ExpectedPanic, + IncrementOrPanic::UnexpectedPanic, + ]; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + dst.write_clone_of_slice(&src); + })); + + drop(src); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[derive(Clone)] +struct Bomb; + +impl Drop for Bomb { + fn drop(&mut self) { + panic!("dropped a bomb! kaboom!") + } +} + +#[test] +fn uninit_write_clone_of_slice_no_drop() { + let mut dst = [MaybeUninit::uninit()]; + let src = [Bomb]; + + dst.write_clone_of_slice(&src); + + forget(src); +} + +#[test] +fn uninit_fill() { + let mut dst = [MaybeUninit::new(255); 64]; + let expect = [0; 64]; + + assert_eq!(MaybeUninit::fill(&mut dst, 0), &expect); +} + +#[cfg(panic = "unwind")] +struct CloneUntilPanic { + limit: usize, + rc: Rc<()>, +} + +#[cfg(panic = "unwind")] +impl Clone for CloneUntilPanic { + fn clone(&self) -> Self { + if Rc::strong_count(&self.rc) >= self.limit { + panic!("expected panic on clone"); + } + Self { limit: self.limit, rc: self.rc.clone() } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_clone_panic_drop() { + use std::panic; + + let rc = Rc::new(()); + + let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + + let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::fill(&mut dst, src); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_clone_no_drop_clones() { + let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + + MaybeUninit::fill(&mut dst, Bomb); +} + +#[test] +fn uninit_fill_with() { + let mut dst = [MaybeUninit::new(255); 64]; + let expect = [0; 64]; + + assert_eq!(MaybeUninit::fill_with(&mut dst, || 0), &expect); +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_with_mid_panic() { + use std::panic; + + let rc = Rc::new(()); + + let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + + let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::fill_with(&mut dst, || src.clone()); + })); + + drop(src); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_with_no_drop() { + let mut dst = [MaybeUninit::uninit()]; + let src = Bomb; + + MaybeUninit::fill_with(&mut dst, || src.clone()); + + forget(src); +} + +#[test] +fn uninit_fill_from() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 64]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src); + assert_eq!(remainder.len(), 0); +} + +#[test] +fn uninit_fill_from_partial() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 48]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src); + assert_eq!(remainder.len(), 16); +} + +#[test] +fn uninit_over_fill() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 72]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src[0..64]); + assert_eq!(remainder.len(), 0); +} + +#[test] +fn uninit_empty_fill() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 0]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src[0..0]); + assert_eq!(remainder.len(), 64); +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_from_mid_panic() { + use std::panic; + + struct IterUntilPanic { + limit: usize, + rc: Rc<()>, + } + + impl Iterator for IterUntilPanic { + type Item = Rc<()>; + fn next(&mut self) -> Option { + if Rc::strong_count(&self.rc) >= self.limit { + panic!("expected panic on next"); + } + Some(self.rc.clone()) + } + } + + let rc = Rc::new(()); + + let mut dst = [ + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + ]; + + let src = IterUntilPanic { limit: 3, rc: rc.clone() }; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::fill_from(&mut dst, src); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on next" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_from_no_drop() { + let mut dst = [MaybeUninit::uninit()]; + let src = [Bomb]; + + MaybeUninit::fill_from(&mut dst, src.iter()); + + forget(src); +} + +#[test] +fn uninit_const_assume_init_read() { + const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() }; + assert_eq!(FOO, 42); +} + +#[test] +fn const_maybe_uninit() { + use std::ptr; + + #[derive(Debug, PartialEq)] + struct Foo { + x: u8, + y: u8, + } + + const FIELD_BY_FIELD: Foo = unsafe { + let mut val = MaybeUninit::uninit(); + init_y(&mut val); // order shouldn't matter + init_x(&mut val); + val.assume_init() + }; + + const fn init_x(foo: &mut MaybeUninit) { + unsafe { + *ptr::addr_of_mut!((*foo.as_mut_ptr()).x) = 1; + } + } + + const fn init_y(foo: &mut MaybeUninit) { + unsafe { + *ptr::addr_of_mut!((*foo.as_mut_ptr()).y) = 2; + } + } + + assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 }); +} + +#[test] +fn offset_of() { + #[repr(C)] + struct Foo { + x: u8, + y: u16, + z: Bar, + } + + #[repr(C)] + struct Bar(u8, u8); + + assert_eq!(offset_of!(Foo, x), 0); + assert_eq!(offset_of!(Foo, y), 2); + assert_eq!(offset_of!(Foo, z.0), 4); + assert_eq!(offset_of!(Foo, z.1), 5); + + // Layout of tuples is unstable + assert!(offset_of!((u8, u16), 0) <= size_of::<(u8, u16)>() - 1); + assert!(offset_of!((u8, u16), 1) <= size_of::<(u8, u16)>() - 2); + + #[repr(C)] + struct Generic { + x: u8, + y: u32, + z: T, + } + + trait Trait {} + + // Ensure that this type of generics works + fn offs_of_z() -> usize { + offset_of!(Generic, z) + } + + assert_eq!(offset_of!(Generic, z), 8); + assert_eq!(offs_of_z::(), 8); + + // Ensure that it works with the implicit lifetime in `Box`. + assert_eq!(offset_of!(Generic>, z), 8); +} + +#[test] +fn offset_of_union() { + #[repr(C)] + union Foo { + x: u8, + y: u16, + z: Bar, + } + + #[repr(C)] + #[derive(Copy, Clone)] + struct Bar(u8, u8); + + assert_eq!(offset_of!(Foo, x), 0); + assert_eq!(offset_of!(Foo, y), 0); + assert_eq!(offset_of!(Foo, z.0), 0); + assert_eq!(offset_of!(Foo, z.1), 1); +} + +#[test] +fn offset_of_dst() { + #[repr(C)] + struct Alpha { + x: u8, + y: u16, + z: [u8], + } + + trait Trait {} + + #[repr(C)] + struct Beta { + x: u8, + y: u16, + z: dyn Trait, + } + + extern "C" { + type Extern; + } + + #[repr(C)] + struct Gamma { + x: u8, + y: u16, + z: Extern, + } + + assert_eq!(offset_of!(Alpha, x), 0); + assert_eq!(offset_of!(Alpha, y), 2); + + assert_eq!(offset_of!(Beta, x), 0); + assert_eq!(offset_of!(Beta, y), 2); + + assert_eq!(offset_of!(Gamma, x), 0); + assert_eq!(offset_of!(Gamma, y), 2); +} + +#[test] +fn offset_of_packed() { + #[repr(C, packed)] + struct Foo { + x: u8, + y: u16, + } + + assert_eq!(offset_of!(Foo, x), 0); + assert_eq!(offset_of!(Foo, y), 1); +} + +#[test] +fn offset_of_projection() { + #[repr(C)] + struct Foo { + x: u8, + y: u16, + } + + trait Projector { + type Type; + } + + impl Projector for () { + type Type = Foo; + } + + assert_eq!(offset_of!(<() as Projector>::Type, x), 0); + assert_eq!(offset_of!(<() as Projector>::Type, y), 2); +} + +#[test] +fn offset_of_alias() { + #[repr(C)] + struct Foo { + x: u8, + y: u16, + } + + type Bar = Foo; + + assert_eq!(offset_of!(Bar, x), 0); + assert_eq!(offset_of!(Bar, y), 2); +} + +#[test] +fn const_offset_of() { + #[repr(C)] + struct Foo { + x: u8, + y: u16, + } + + const X_OFFSET: usize = offset_of!(Foo, x); + const Y_OFFSET: usize = offset_of!(Foo, y); + + assert_eq!(X_OFFSET, 0); + assert_eq!(Y_OFFSET, 2); +} + +#[test] +fn offset_of_without_const_promotion() { + #[repr(C)] + struct Foo { + x: u8, + y: u16, + _scp: SuppressConstPromotion, + } + + // Normally, offset_of is always const promoted. + // The generic parameter prevents this from happening. + // This is needed to test the codegen impl of offset_of + fn inner() { + assert_eq!(offset_of!(Foo, x), 0); + assert_eq!(offset_of!(Foo, y), 2); + } + + inner::<()>(); +} + +#[test] +fn offset_of_addr() { + #[repr(C)] + struct Foo { + x: u8, + y: u16, + z: Bar, + } + + #[repr(C)] + struct Bar(u8, u8); + + let base = Foo { x: 0, y: 0, z: Bar(0, 0) }; + + assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, x), ptr::addr_of!(base.x).addr()); + assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, y), ptr::addr_of!(base.y).addr()); + assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.0), ptr::addr_of!(base.z.0).addr()); + assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.1), ptr::addr_of!(base.z.1).addr()); +} + +#[test] +fn const_maybe_uninit_zeroed() { + // Sanity check for `MaybeUninit::zeroed` in a realistic const situation (plugin array term) + + // It is crucial that this type has no padding! + #[repr(C)] + struct Foo { + a: Option<&'static u8>, + b: Bar, + c: f32, + _pad: u32, + d: *const u8, + } + + #[repr(C)] + struct Bar(usize); + + struct FooPtr(*const Foo); + unsafe impl Sync for FooPtr {} + + static UNINIT: FooPtr = FooPtr([unsafe { MaybeUninit::zeroed().assume_init() }].as_ptr()); + const SIZE: usize = size_of::(); + + assert_eq!(unsafe { (*UNINIT.0.cast::<[[u8; SIZE]; 1]>())[0] }, [0u8; SIZE]); +} diff --git a/library/coretests/tests/net/ip_addr.rs b/library/coretests/tests/net/ip_addr.rs new file mode 100644 index 00000000000..f01b43282ec --- /dev/null +++ b/library/coretests/tests/net/ip_addr.rs @@ -0,0 +1,1092 @@ +use core::net::{ + IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope, SocketAddr, SocketAddrV4, SocketAddrV6, +}; +use core::str::FromStr; + +use super::{sa4, sa6}; + +#[test] +fn test_from_str_ipv4() { + assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); + assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); + assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); + + // out of range + let none: Option = "256.0.0.1".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "255.0.0".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "255.0.0.1.2".parse().ok(); + assert_eq!(None, none); + // no number between dots + let none: Option = "255.0..1".parse().ok(); + assert_eq!(None, none); + // octal + let none: Option = "255.0.0.01".parse().ok(); + assert_eq!(None, none); + // octal zero + let none: Option = "255.0.0.00".parse().ok(); + assert_eq!(None, none); + let none: Option = "255.0.00.0".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse()); + + // too long group + let none: Option = "::00000".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "1:2:3:4:5:6:7".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); + assert_eq!(None, none); + // triple colon + let none: Option = "1:2:::6:7:8".parse().ok(); + assert_eq!(None, none); + // two double colons + let none: Option = "1:2::6::8".parse().ok(); + assert_eq!(None, none); + // `::` indicating zero groups of zeros + let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_ipv4_in_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse()); + assert_eq!( + Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + "64:ff9b::192.0.2.33".parse() + ); + assert_eq!( + Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + "2001:db8:122:c000:2:2100:192.0.2.33".parse() + ); + + // colon after v4 + let none: Option = "::127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // not enough groups + let none: Option = "1:2:3:4:5:127.0.0.1".parse().ok(); + assert_eq!(None, none); + // too many groups + let none: Option = "1:2:3:4:5:6:7:127.0.0.1".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_socket_addr() { + assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!( + Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse()); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)), + "[::127.0.0.1]:22".parse() + ); + + // without port + let none: Option = "127.0.0.1".parse().ok(); + assert_eq!(None, none); + // without port + let none: Option = "127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // wrong brackets around v4 + let none: Option = "[127.0.0.1]:22".parse().ok(); + assert_eq!(None, none); + // port out of range + let none: Option = "127.0.0.1:123456".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn ipv4_addr_to_string() { + assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1"); + // Short address + assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); + // Long address + assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); + + // Test padding + assert_eq!(format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); + assert_eq!(format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); +} + +#[test] +fn ipv6_addr_to_string() { + // ipv4-mapped address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); + + // ipv4-compatible address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::c000:280"); + + // v6 address with no zero segments + assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); + + // longest possible IPv6 length + assert_eq!( + Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(), + "1111:2222:3333:4444:5555:6666:7777:8888" + ); + // padding + assert_eq!(format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 "); + assert_eq!(format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8"); + + // reduce a single run of zeros + assert_eq!( + "ae::ffff:102:304", + Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() + ); + + // don't reduce just a single zero segment + assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); + + // 'any' address + assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // loopback address + assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); + + // ends in zeros + assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // two runs of zeros, second one is longer + assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); + + // two runs of zeros, equal length + assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); + + // don't prefix `0x` to each segment in `dbg!`. + assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8))); +} + +#[test] +fn ipv4_to_ipv6() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() + ); +} + +#[test] +fn ipv6_to_ipv4_mapped() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None); +} + +#[test] +fn ipv6_to_ipv4() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); +} + +#[test] +fn ip_properties() { + macro_rules! ip { + ($s:expr) => { + IpAddr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + let benchmarking: u8 = 1 << 5; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & doc) == doc { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + }}; + } + + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + let benchmarking: u8 = 1 << 5; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7"); + check!("127.1.2.3", loopback); + check!("172.31.254.253"); + check!("169.254.253.242"); + check!("192.0.2.183", doc); + check!("192.1.2.183", global); + check!("192.168.254.253"); + check!("198.51.100.0", doc); + check!("203.0.113.0", doc); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + check!("239.255.255.255", global | multicast); + check!("255.255.255.255"); + // make sure benchmarking addresses are not global + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); + // make sure addresses reserved for protocol assignment are not global + check!("192.0.0.0"); + check!("192.0.0.255"); + check!("192.0.0.100"); + // make sure reserved addresses are not global + check!("240.0.0.0"); + check!("251.54.1.76"); + check!("254.255.255.255"); + // make sure shared addresses are not global + check!("100.64.0.0"); + check!("100.127.255.255"); + check!("100.100.100.0"); + + check!("::", unspec); + check!("::1", loopback); + check!("::2", global); + check!("1::", global); + check!("fc00::"); + check!("fdff:ffff::"); + check!("fe80:ffff::"); + check!("febf:ffff::"); + check!("fec0::", global); + check!("ff01::", global | multicast); + check!("ff02::", global | multicast); + check!("ff03::", global | multicast); + check!("ff04::", global | multicast); + check!("ff05::", global | multicast); + check!("ff08::", global | multicast); + check!("ff0e::", global | multicast); + check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff", doc); + check!("2001:2::ac32:23ff:21", benchmarking); + check!("102:304:506:708:90a:b0c:d0e:f10", global); +} + +#[test] +fn ipv4_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv4Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & private) == private { + assert!(ip!($s).is_private()); + } else { + assert!(!ip!($s).is_private()); + } + + if ($mask & link_local) == link_local { + assert!(ip!($s).is_link_local()); + } else { + assert!(!ip!($s).is_link_local()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & broadcast) == broadcast { + assert!(ip!($s).is_broadcast()); + } else { + assert!(!ip!($s).is_broadcast()); + } + + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + + if ($mask & reserved) == reserved { + assert!(ip!($s).is_reserved()); + } else { + assert!(!ip!($s).is_reserved()); + } + + if ($mask & shared) == shared { + assert!(ip!($s).is_shared()); + } else { + assert!(!ip!($s).is_shared()); + } + }}; + } + + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7", private); + check!("127.1.2.3", loopback); + check!("172.31.254.253", private); + check!("169.254.253.242", link_local); + check!("192.0.2.183", documentation); + check!("192.1.2.183", global); + check!("192.168.254.253", private); + check!("198.51.100.0", documentation); + check!("203.0.113.0", documentation); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + check!("239.255.255.255", global | multicast); + check!("255.255.255.255", broadcast); + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); + check!("192.0.0.0"); + check!("192.0.0.8"); + check!("192.0.0.9", global); + check!("192.0.0.10", global); + check!("192.0.0.11"); + check!("192.0.0.255"); + check!("192.0.0.100"); + check!("240.0.0.0", reserved); + check!("251.54.1.76", reserved); + check!("254.255.255.255", reserved); + check!("100.64.0.0", shared); + check!("100.127.255.255", shared); + check!("100.100.100.0", shared); +} + +#[test] +fn ipv6_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv6Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr, &[$($octet:expr),*]) => { + check!($s, &[$($octet),*], 0); + }; + + ($s:expr, &[$($octet:expr),*], $mask:expr) => { + assert_eq!($s, ip!($s).to_string()); + let octets = &[$($octet),*]; + assert_eq!(&ip!($s).octets(), octets); + assert_eq!(Ipv6Addr::from(*octets), ip!($s)); + assert_eq!(Ipv6Addr::from_octets(*octets), ip!($s)); + + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let benchmarking: u32 = 1 << 16; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + let multicast: u32 = multicast_interface_local + | multicast_admin_local + | multicast_global + | multicast_link_local + | multicast_realm_local + | multicast_site_local + | multicast_organization_local; + let ipv4_mapped: u32 = 1 << 17; + + if ($mask & unspecified) == unspecified { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + if ($mask & unique_local) == unique_local { + assert!(ip!($s).is_unique_local()); + } else { + assert!(!ip!($s).is_unique_local()); + } + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + if ($mask & unicast_link_local) == unicast_link_local { + assert!(ip!($s).is_unicast_link_local()); + } else { + assert!(!ip!($s).is_unicast_link_local()); + } + if ($mask & unicast_global) == unicast_global { + assert!(ip!($s).is_unicast_global()); + } else { + assert!(!ip!($s).is_unicast_global()); + } + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + if ($mask & multicast) != 0 { + assert!(ip!($s).multicast_scope().is_some()); + assert!(ip!($s).is_multicast()); + } else { + assert!(ip!($s).multicast_scope().is_none()); + assert!(!ip!($s).is_multicast()); + } + if ($mask & multicast_interface_local) == multicast_interface_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::InterfaceLocal); + } + if ($mask & multicast_link_local) == multicast_link_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::LinkLocal); + } + if ($mask & multicast_realm_local) == multicast_realm_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::RealmLocal); + } + if ($mask & multicast_admin_local) == multicast_admin_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::AdminLocal); + } + if ($mask & multicast_site_local) == multicast_site_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::SiteLocal); + } + if ($mask & multicast_organization_local) == multicast_organization_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::OrganizationLocal); + } + if ($mask & multicast_global) == multicast_global { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Global); + } + if ($mask & ipv4_mapped) == ipv4_mapped { + assert!(ip!($s).is_ipv4_mapped()); + } else { + assert!(!ip!($s).is_ipv4_mapped()); + } + } + } + + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let benchmarking: u32 = 1 << 16; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + let ipv4_mapped: u32 = 1 << 17; + + check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); + + check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); + + check!("::2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); + + check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); + + check!( + "::ffff:127.0.0.1", + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1], + unicast_global | ipv4_mapped + ); + + check!( + "64:ff9b:1::", + &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_global + ); + + check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!( + "2001:1::1", + &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + global | unicast_global + ); + + check!( + "2001:1::2", + &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], + global | unicast_global + ); + + check!( + "2001:3::", + &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!( + "2001:4:112::", + &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!( + "2001:20::", + &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + check!( + "2001:30::", + &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + check!("2001:40::", &[0x20, 1, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!( + "2001:200::", + &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + global | unicast_global + ); + + check!("2002::", &[0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global); + + check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); + + check!( + "fdff:ffff::", + &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unique_local + ); + + check!( + "fe80:ffff::", + &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); + + check!( + "febf:ffff::", + &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); + + check!( + "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + &[ + 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local + ); + + check!( + "fe80::ffff:ffff:ffff:ffff", + &[ + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local + ); + + check!( + "fe80:0:0:1::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "fec0::", + &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_global | global + ); + + check!( + "ff01::", + &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_interface_local | global + ); + + check!( + "ff02::", + &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_link_local | global + ); + + check!( + "ff03::", + &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_realm_local | global + ); + + check!( + "ff04::", + &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_admin_local | global + ); + + check!( + "ff05::", + &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_site_local | global + ); + + check!( + "ff08::", + &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_organization_local | global + ); + + check!( + "ff0e::", + &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_global | global + ); + + check!( + "2001:db8:85a3::8a2e:370:7334", + &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], + documentation + ); + + check!( + "3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff", + &[ + 0x3f, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + documentation + ); + + check!( + "2001:2::ac32:23ff:21", + &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21], + benchmarking + ); + + check!( + "102:304:506:708:90a:b0c:d0e:f10", + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + global | unicast_global + ); +} + +#[test] +fn test_ipv4_to_int() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(u32::from(a), 0x11223344); +} + +#[test] +fn test_int_to_ipv4() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(Ipv4Addr::from(0x11223344), a); +} + +#[test] +fn test_ipv6_to_int() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); +} + +#[test] +fn test_int_to_ipv6() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); +} + +#[test] +fn ipv4_from_constructors() { + assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); + assert!(Ipv4Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); + assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); + assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); + assert!(Ipv4Addr::BROADCAST.is_broadcast()); +} + +#[test] +fn ipv6_from_constructors() { + assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + assert!(Ipv6Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); +} + +#[test] +fn ipv4_from_octets() { + assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)); + assert_eq!(Ipv4Addr::from_octets([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)); +} + +#[test] +fn ipv6_from_segments() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let from_u16s_explicit = + Ipv6Addr::from_segments([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); + assert_eq!(new, from_u16s); + assert_eq!(new, from_u16s_explicit); +} + +#[test] +fn ipv6_from_octets() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let from_u8s = Ipv6Addr::from([ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff, + ]); + let from_u16s_explicit = + Ipv6Addr::from_segments([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let from_u8s_explicit = Ipv6Addr::from_octets([ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff, + ]); + assert_eq!(from_u16s, from_u8s); + assert_eq!(from_u16s, from_u16s_explicit); + assert_eq!(from_u16s_explicit, from_u8s_explicit); +} + +#[test] +fn cmp() { + let v41 = Ipv4Addr::new(100, 64, 3, 3); + let v42 = Ipv4Addr::new(192, 0, 2, 2); + let v61 = "2001:db8:f00::1002".parse::().unwrap(); + let v62 = "2001:db8:f00::2001".parse::().unwrap(); + assert!(v41 < v42); + assert!(v61 < v62); + + assert_eq!(v41, IpAddr::V4(v41)); + assert_eq!(v61, IpAddr::V6(v61)); + assert!(v41 != IpAddr::V4(v42)); + assert!(v61 != IpAddr::V6(v62)); + + assert!(v41 < IpAddr::V4(v42)); + assert!(v61 < IpAddr::V6(v62)); + assert!(IpAddr::V4(v41) < v42); + assert!(IpAddr::V6(v61) < v62); + + assert!(v41 < IpAddr::V6(v61)); + assert!(IpAddr::V4(v41) < v61); +} + +#[test] +fn is_v4() { + let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); + assert!(ip.is_ipv4()); + assert!(!ip.is_ipv6()); +} + +#[test] +fn is_v6() { + let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); + assert!(!ip.is_ipv4()); + assert!(ip.is_ipv6()); +} + +#[test] +fn ipv4_const() { + // test that the methods of `Ipv4Addr` are usable in a const context + + const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); + + const OCTETS: [u8; 4] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [127, 0, 0, 1]); + + const FROM_OCTETS: Ipv4Addr = Ipv4Addr::from_octets(OCTETS); + assert_eq!(IP_ADDRESS, FROM_OCTETS); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_PRIVATE: bool = IP_ADDRESS.is_private(); + assert!(!IS_PRIVATE); + + const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local(); + assert!(!IS_LINK_LOCAL); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_SHARED: bool = IP_ADDRESS.is_shared(); + assert!(!IS_SHARED); + + const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + + const IS_RESERVED: bool = IP_ADDRESS.is_reserved(); + assert!(!IS_RESERVED); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast(); + assert!(!IS_BROADCAST); + + const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); + assert_eq!( + IP_V6_COMPATIBLE, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1]) + ); + + const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); + assert_eq!( + IP_V6_MAPPED, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1]) + ); +} + +#[test] +fn ipv6_const() { + // test that the methods of `Ipv6Addr` are usable in a const context + + const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); + + const SEGMENTS: [u16; 8] = IP_ADDRESS.segments(); + assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]); + + const FROM_SEGMENTS: Ipv6Addr = Ipv6Addr::from_segments(SEGMENTS); + assert_eq!(IP_ADDRESS, FROM_SEGMENTS); + + const OCTETS: [u8; 16] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); + + const FROM_OCTETS: Ipv6Addr = Ipv6Addr::from_octets(OCTETS); + assert_eq!(IP_ADDRESS, FROM_OCTETS); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local(); + assert!(!IS_UNIQUE_LOCAL); + + const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); + assert!(!IS_UNICAST_LINK_LOCAL); + + const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + + const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global(); + assert!(!IS_UNICAST_GLOBAL); + + const MULTICAST_SCOPE: Option = IP_ADDRESS.multicast_scope(); + assert_eq!(MULTICAST_SCOPE, None); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IS_IPV4_MAPPED: bool = IP_ADDRESS.is_ipv4_mapped(); + assert!(!IS_IPV4_MAPPED); + + const IP_V4: Option = IP_ADDRESS.to_ipv4(); + assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); +} + +#[test] +fn ip_const() { + // test that the methods of `IpAddr` are usable in a const context + + const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IS_IP_V4: bool = IP_ADDRESS.is_ipv4(); + assert!(IS_IP_V4); + + const IS_IP_V6: bool = IP_ADDRESS.is_ipv6(); + assert!(!IS_IP_V6); +} + +#[test] +fn structural_match() { + // test that all IP types can be structurally matched upon + + const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST; + match IPV4 { + Ipv4Addr::LOCALHOST => {} + _ => unreachable!(), + } + + const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST; + match IPV6 { + Ipv6Addr::LOCALHOST => {} + _ => unreachable!(), + } + + const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); + match IP { + IpAddr::V4(Ipv4Addr::LOCALHOST) => {} + _ => unreachable!(), + } +} diff --git a/library/coretests/tests/net/mod.rs b/library/coretests/tests/net/mod.rs new file mode 100644 index 00000000000..8f17bbe5548 --- /dev/null +++ b/library/coretests/tests/net/mod.rs @@ -0,0 +1,13 @@ +use core::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; + +mod ip_addr; +mod parser; +mod socket_addr; + +pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr { + SocketAddr::V4(SocketAddrV4::new(a, p)) +} + +pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr { + SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0)) +} diff --git a/library/coretests/tests/net/parser.rs b/library/coretests/tests/net/parser.rs new file mode 100644 index 00000000000..e03959ac77c --- /dev/null +++ b/library/coretests/tests/net/parser.rs @@ -0,0 +1,150 @@ +// FIXME: These tests are all excellent candidates for AFL fuzz testing + +use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use core::str::FromStr; + +const PORT: u16 = 8080; +const SCOPE_ID: u32 = 1337; + +const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1); +const IPV4_STR: &str = "192.168.0.1"; +const IPV4_STR_PORT: &str = "192.168.0.1:8080"; +const IPV4_STR_WITH_OCTAL: &str = "0127.0.0.1"; +const IPV4_STR_WITH_HEX: &str = "0x10.0.0.1"; + +const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1); +const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; +const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; +const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; +const IPV6_STR_V4_WITH_OCTAL: &str = "2001:db8::0127.0.0.1"; +const IPV6_STR_V4_WITH_HEX: &str = "2001:db8::0x10.0.0.1"; +const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; +const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080"; + +#[test] +fn parse_ipv4() { + let result: Ipv4Addr = IPV4_STR.parse().unwrap(); + assert_eq!(result, IPV4); + + assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err()); + assert!(Ipv4Addr::from_str(IPV4_STR_WITH_OCTAL).is_err()); + assert!(Ipv4Addr::from_str(IPV4_STR_WITH_HEX).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_ipv6() { + let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap(); + assert_eq!(result, IPV6); + + let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap(); + assert_eq!(result, IPV6); + + let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap(); + assert_eq!(result, IPV6); + + assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_OCTAL).is_err()); + assert!(Ipv6Addr::from_str(IPV6_STR_V4_WITH_HEX).is_err()); + assert!(Ipv6Addr::from_str(IPV4_STR).is_err()); + assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err()); + assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_ip() { + let result: IpAddr = IPV4_STR.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV4)); + + let result: IpAddr = IPV6_STR_FULL.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + let result: IpAddr = IPV6_STR_V4.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + assert!(IpAddr::from_str(IPV4_STR_PORT).is_err()); + assert!(IpAddr::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_socket_v4() { + let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddrV4::new(IPV4, PORT)); + + assert!(SocketAddrV4::from_str(IPV4_STR).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_socket_v6() { + assert_eq!(IPV6_STR_PORT.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, 0))); + assert_eq!(IPV6_STR_PORT_SCOPE_ID.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, SCOPE_ID))); + + assert!(SocketAddrV6::from_str(IPV4_STR).is_err()); + assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err()); +} + +#[test] +fn parse_socket() { + let result: SocketAddr = IPV4_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddr::from((IPV4, PORT))); + + let result: SocketAddr = IPV6_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddr::from((IPV6, PORT))); + + assert!(SocketAddr::from_str(IPV4_STR).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_V4).is_err()); +} + +#[test] +fn ipv6_corner_cases() { + let result: Ipv6Addr = "1::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "1:1::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "::1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + + let result: Ipv6Addr = "::1:1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1)); + + let result: Ipv6Addr = "::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "::192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1)); + + let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1)); + + let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1)); +} + +// Things that might not seem like failures but are +#[test] +fn ipv6_corner_failures() { + // No IP address before the :: + assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err()); + + // :: must have at least 1 set of zeroes + assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err()); + + // Need brackets for a port + assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err()); +} diff --git a/library/coretests/tests/net/socket_addr.rs b/library/coretests/tests/net/socket_addr.rs new file mode 100644 index 00000000000..3d013d37e04 --- /dev/null +++ b/library/coretests/tests/net/socket_addr.rs @@ -0,0 +1,244 @@ +use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; + +#[test] +fn ipv4_socket_addr_to_string() { + // Shortest possible IPv4 length. + assert_eq!(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0).to_string(), "0.0.0.0:0"); + + // Longest possible IPv4 length. + assert_eq!( + SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), u16::MAX).to_string(), + "255.255.255.255:65535" + ); + + // Test padding. + assert_eq!( + &format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), + "1.1.1.1:53 " + ); + assert_eq!( + &format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)), + " 1.1.1.1:53" + ); +} + +#[test] +fn ipv6_socket_addr_to_string() { + // IPv4-mapped address. + assert_eq!( + SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280), 8080, 0, 0) + .to_string(), + "[::ffff:192.0.2.128]:8080" + ); + + // IPv4-compatible address. + assert_eq!( + SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(), + "[::c000:280]:8080" + ); + + // IPv6 address with no zero segments. + assert_eq!( + SocketAddrV6::new(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15), 80, 0, 0).to_string(), + "[8:9:a:b:c:d:e:f]:80" + ); + + // Shortest possible IPv6 length. + assert_eq!(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0).to_string(), "[::]:0"); + + // Longest possible IPv6 length. + assert_eq!( + SocketAddrV6::new( + Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888), + u16::MAX, + u32::MAX, + u32::MAX, + ) + .to_string(), + "[1111:2222:3333:4444:5555:6666:7777:8888%4294967295]:65535" + ); + + // Test padding. + assert_eq!( + &format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), + "[1:2:3:4:5:6:7:8]:9 " + ); + assert_eq!( + &format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)), + " [1:2:3:4:5:6:7:8]:9" + ); +} + +#[test] +fn set_ip() { + fn ip4(low: u8) -> Ipv4Addr { + Ipv4Addr::new(77, 88, 21, low) + } + fn ip6(low: u16) -> Ipv6Addr { + Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) + } + + let mut v4 = SocketAddrV4::new(ip4(11), 80); + assert_eq!(v4.ip(), &ip4(11)); + v4.set_ip(ip4(12)); + assert_eq!(v4.ip(), &ip4(12)); + + let mut addr = SocketAddr::V4(v4); + assert_eq!(addr.ip(), IpAddr::V4(ip4(12))); + addr.set_ip(IpAddr::V4(ip4(13))); + assert_eq!(addr.ip(), IpAddr::V4(ip4(13))); + addr.set_ip(IpAddr::V6(ip6(14))); + assert_eq!(addr.ip(), IpAddr::V6(ip6(14))); + + let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0); + assert_eq!(v6.ip(), &ip6(1)); + v6.set_ip(ip6(2)); + assert_eq!(v6.ip(), &ip6(2)); + + let mut addr = SocketAddr::V6(v6); + assert_eq!(addr.ip(), IpAddr::V6(ip6(2))); + addr.set_ip(IpAddr::V6(ip6(3))); + assert_eq!(addr.ip(), IpAddr::V6(ip6(3))); + addr.set_ip(IpAddr::V4(ip4(4))); + assert_eq!(addr.ip(), IpAddr::V4(ip4(4))); +} + +#[test] +fn set_port() { + let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80); + assert_eq!(v4.port(), 80); + v4.set_port(443); + assert_eq!(v4.port(), 443); + + let mut addr = SocketAddr::V4(v4); + assert_eq!(addr.port(), 443); + addr.set_port(8080); + assert_eq!(addr.port(), 8080); + + let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0); + assert_eq!(v6.port(), 80); + v6.set_port(443); + assert_eq!(v6.port(), 443); + + let mut addr = SocketAddr::V6(v6); + assert_eq!(addr.port(), 443); + addr.set_port(8080); + assert_eq!(addr.port(), 8080); +} + +#[test] +fn set_flowinfo() { + let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0); + assert_eq!(v6.flowinfo(), 10); + v6.set_flowinfo(20); + assert_eq!(v6.flowinfo(), 20); +} + +#[test] +fn set_scope_id() { + let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10); + assert_eq!(v6.scope_id(), 10); + v6.set_scope_id(20); + assert_eq!(v6.scope_id(), 20); +} + +#[test] +fn is_v4() { + let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); + assert!(v4.is_ipv4()); + assert!(!v4.is_ipv6()); +} + +#[test] +fn is_v6() { + let v6 = SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), + 80, + 10, + 0, + )); + assert!(!v6.is_ipv4()); + assert!(v6.is_ipv6()); +} + +#[test] +fn socket_v4_to_str() { + let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080); + + assert_eq!(format!("{socket}"), "192.168.0.1:8080"); + assert_eq!(format!("{socket:<20}"), "192.168.0.1:8080 "); + assert_eq!(format!("{socket:>20}"), " 192.168.0.1:8080"); + assert_eq!(format!("{socket:^20}"), " 192.168.0.1:8080 "); + assert_eq!(format!("{socket:.10}"), "192.168.0."); +} + +#[test] +fn socket_v6_to_str() { + let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0); + + assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{socket:.15}"), "[2a02:6b8:0:1::"); + + socket.set_scope_id(5); + + assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1%5]:53"); + assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1%5]:53 "); + assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1%5]:53"); + assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1%5]:53 "); + assert_eq!(format!("{socket:.18}"), "[2a02:6b8:0:1::1%5"); +} + +#[test] +fn compare() { + let v4_1 = "224.120.45.1:23456".parse::().unwrap(); + let v4_2 = "224.210.103.5:12345".parse::().unwrap(); + let v4_3 = "224.210.103.5:23456".parse::().unwrap(); + let v6_1 = "[2001:db8:f00::1002]:23456".parse::().unwrap(); + let v6_2 = "[2001:db8:f00::2001]:12345".parse::().unwrap(); + let v6_3 = "[2001:db8:f00::2001]:23456".parse::().unwrap(); + let v6_4 = "[2001:db8:f00::2001%42]:23456".parse::().unwrap(); + let mut v6_5 = "[2001:db8:f00::2001]:23456".parse::().unwrap(); + v6_5.set_flowinfo(17); + + // equality + assert_eq!(v4_1, v4_1); + assert_eq!(v6_1, v6_1); + assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1)); + assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); + assert!(v4_1 != v4_2); + assert!(v6_1 != v6_2); + assert!(v6_3 != v6_4); + assert!(v6_3 != v6_5); + + // compare different addresses + assert!(v4_1 < v4_2); + assert!(v6_1 < v6_2); + assert!(v4_2 > v4_1); + assert!(v6_2 > v6_1); + + // compare the same address with different ports + assert!(v4_2 < v4_3); + assert!(v6_2 < v6_3); + assert!(v4_3 > v4_2); + assert!(v6_3 > v6_2); + + // compare different addresses with the same port + assert!(v4_1 < v4_3); + assert!(v6_1 < v6_3); + assert!(v4_3 > v4_1); + assert!(v6_3 > v6_1); + + // compare the same address with different scope_id + assert!(v6_3 < v6_4); + + // compare the same address with different flowinfo + assert!(v6_3 < v6_5); + + // compare with an inferred right-hand side + assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap()); + assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap()); + assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap()); +} diff --git a/library/coretests/tests/nonzero.rs b/library/coretests/tests/nonzero.rs new file mode 100644 index 00000000000..43c279053d8 --- /dev/null +++ b/library/coretests/tests/nonzero.rs @@ -0,0 +1,367 @@ +use core::num::{IntErrorKind, NonZero}; +use core::option::Option::None; +use std::mem::size_of; + +#[test] +fn test_create_nonzero_instance() { + let _a = unsafe { NonZero::new_unchecked(21) }; +} + +#[test] +fn test_size_nonzero_in_option() { + assert_eq!(size_of::>(), size_of::>>()); + assert_eq!(size_of::>(), size_of::>>()); +} + +#[test] +fn test_match_on_nonzero_option() { + let a = Some(unsafe { NonZero::::new_unchecked(42) }); + match a { + Some(val) => assert_eq!(val.get(), 42), + None => panic!("unexpected None while matching on Some(NonZero(_))"), + } + + match unsafe { Some(NonZero::::new_unchecked(43)) } { + Some(val) => assert_eq!(val.get(), 43), + None => panic!("unexpected None while matching on Some(NonZero(_))"), + } +} + +#[test] +fn test_match_option_empty_vec() { + let a: Option> = Some(vec![]); + match a { + None => panic!("unexpected None while matching on Some(vec![])"), + _ => {} + } +} + +#[test] +fn test_match_option_vec() { + let a = Some(vec![1, 2, 3, 4]); + match a { + Some(v) => assert_eq!(v, [1, 2, 3, 4]), + None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])"), + } +} + +#[test] +fn test_match_option_rc() { + use std::rc::Rc; + + let five = Rc::new(5); + match Some(five) { + Some(r) => assert_eq!(*r, 5), + None => panic!("unexpected None while matching on Some(Rc::new(5))"), + } +} + +#[test] +fn test_match_option_arc() { + use std::sync::Arc; + + let five = Arc::new(5); + match Some(five) { + Some(a) => assert_eq!(*a, 5), + None => panic!("unexpected None while matching on Some(Arc::new(5))"), + } +} + +#[test] +fn test_match_option_empty_string() { + let a = Some(String::new()); + match a { + None => panic!("unexpected None while matching on Some(String::new())"), + _ => {} + } +} + +#[test] +fn test_match_option_string() { + let five = "Five".to_string(); + match Some(five) { + Some(s) => assert_eq!(s, "Five"), + None => panic!("{}", "unexpected None while matching on Some(String { ... })"), + } +} + +mod atom { + use core::num::NonZero; + + #[derive(PartialEq, Eq)] + pub struct Atom { + index: NonZero, // private + } + + pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZero::new_unchecked(7) } }; +} + +macro_rules! atom { + ("foo") => { + atom::FOO_ATOM + }; +} + +#[test] +fn test_match_nonzero_const_pattern() { + match atom!("foo") { + // Using as a pattern is supported by the compiler: + atom!("foo") => {} + _ => panic!("Expected the const item as a pattern to match."), + } +} + +#[test] +fn test_from_nonzero() { + let nz = NonZero::new(1).unwrap(); + let num: u32 = nz.into(); + assert_eq!(num, 1u32); +} + +#[test] +fn test_from_signed_nonzero() { + let nz = NonZero::new(1).unwrap(); + let num: i32 = nz.into(); + assert_eq!(num, 1i32); +} + +#[test] +fn test_from_str() { + assert_eq!("123".parse::>(), Ok(NonZero::new(123).unwrap())); + assert_eq!( + "0".parse::>().err().map(|e| e.kind().clone()), + Some(IntErrorKind::Zero) + ); + assert_eq!( + "-1".parse::>().err().map(|e| e.kind().clone()), + Some(IntErrorKind::InvalidDigit) + ); + assert_eq!( + "-129".parse::>().err().map(|e| e.kind().clone()), + Some(IntErrorKind::NegOverflow) + ); + assert_eq!( + "257".parse::>().err().map(|e| e.kind().clone()), + Some(IntErrorKind::PosOverflow) + ); +} + +#[test] +fn test_nonzero_bitor() { + let nz_alt = NonZero::new(0b1010_1010).unwrap(); + let nz_low = NonZero::new(0b0000_1111).unwrap(); + + let both_nz: NonZero = nz_alt | nz_low; + assert_eq!(both_nz.get(), 0b1010_1111); + + let rhs_int: NonZero = nz_low | 0b1100_0000u8; + assert_eq!(rhs_int.get(), 0b1100_1111); + + let rhs_zero: NonZero = nz_alt | 0u8; + assert_eq!(rhs_zero.get(), 0b1010_1010); + + let lhs_int: NonZero = 0b0110_0110u8 | nz_alt; + assert_eq!(lhs_int.get(), 0b1110_1110); + + let lhs_zero: NonZero = 0u8 | nz_low; + assert_eq!(lhs_zero.get(), 0b0000_1111); +} + +#[test] +fn test_nonzero_bitor_assign() { + let mut target = NonZero::::new(0b1010_1010).unwrap(); + + target |= NonZero::new(0b0000_1111).unwrap(); + assert_eq!(target.get(), 0b1010_1111); + + target |= 0b0001_0000; + assert_eq!(target.get(), 0b1011_1111); + + target |= 0; + assert_eq!(target.get(), 0b1011_1111); +} + +#[test] +fn test_nonzero_from_int_on_success() { + assert_eq!(NonZero::::try_from(5), Ok(NonZero::new(5).unwrap())); + assert_eq!(NonZero::::try_from(5), Ok(NonZero::new(5).unwrap())); + + assert_eq!(NonZero::::try_from(-5), Ok(NonZero::new(-5).unwrap())); + assert_eq!(NonZero::::try_from(-5), Ok(NonZero::new(-5).unwrap())); +} + +#[test] +fn test_nonzero_from_int_on_err() { + assert!(NonZero::::try_from(0).is_err()); + assert!(NonZero::::try_from(0).is_err()); + + assert!(NonZero::::try_from(0).is_err()); + assert!(NonZero::::try_from(0).is_err()); +} + +#[test] +fn nonzero_const() { + // test that the methods of `NonZeroX>` are usable in a const context + // Note: only tests NonZero + + const NONZERO_U8: NonZero = unsafe { NonZero::new_unchecked(5) }; + + const GET: u8 = NONZERO_U8.get(); + assert_eq!(GET, 5); + + const ZERO: Option> = NonZero::new(0); + assert!(ZERO.is_none()); + + const ONE: Option> = NonZero::new(1); + assert!(ONE.is_some()); + + /* FIXME(#110395) + const FROM_NONZERO_U8: u8 = u8::from(NONZERO_U8); + assert_eq!(FROM_NONZERO_U8, 5); + + const NONZERO_CONVERT: NonZero = NonZero::::from(NONZERO_U8); + assert_eq!(NONZERO_CONVERT.get(), 5); + */ +} + +#[test] +fn nonzero_leading_zeros() { + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 7); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 7); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 15); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 15); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 31); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 31); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 63); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 63); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 127); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), 127); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), usize::BITS - 1); + assert_eq!(NonZero::::new(1).unwrap().leading_zeros(), usize::BITS - 1); + + assert_eq!(NonZero::::new(u8::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new(u16::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new(u32::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new(u64::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new(u128::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new(usize::MAX >> 2).unwrap().leading_zeros(), 2); + assert_eq!(NonZero::::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2); + + assert_eq!(NonZero::::new(u8::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(-1i8).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(u16::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(-1i16).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(u32::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(-1i32).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(u64::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(-1i64).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(u128::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(-1i128).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(usize::MAX).unwrap().leading_zeros(), 0); + assert_eq!(NonZero::::new(-1isize).unwrap().leading_zeros(), 0); + + const LEADING_ZEROS: u32 = NonZero::::new(1).unwrap().leading_zeros(); + assert_eq!(LEADING_ZEROS, 15); +} + +#[test] +fn nonzero_trailing_zeros() { + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + assert_eq!(NonZero::::new(1).unwrap().trailing_zeros(), 0); + + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + assert_eq!(NonZero::::new(1 << 2).unwrap().trailing_zeros(), 2); + + assert_eq!(NonZero::::new(1 << 7).unwrap().trailing_zeros(), 7); + assert_eq!(NonZero::::new(1 << 7).unwrap().trailing_zeros(), 7); + assert_eq!(NonZero::::new(1 << 15).unwrap().trailing_zeros(), 15); + assert_eq!(NonZero::::new(1 << 15).unwrap().trailing_zeros(), 15); + assert_eq!(NonZero::::new(1 << 31).unwrap().trailing_zeros(), 31); + assert_eq!(NonZero::::new(1 << 31).unwrap().trailing_zeros(), 31); + assert_eq!(NonZero::::new(1 << 63).unwrap().trailing_zeros(), 63); + assert_eq!(NonZero::::new(1 << 63).unwrap().trailing_zeros(), 63); + assert_eq!(NonZero::::new(1 << 127).unwrap().trailing_zeros(), 127); + assert_eq!(NonZero::::new(1 << 127).unwrap().trailing_zeros(), 127); + + assert_eq!( + NonZero::::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(), + usize::BITS - 1 + ); + assert_eq!( + NonZero::::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(), + usize::BITS - 1 + ); + + const TRAILING_ZEROS: u32 = NonZero::::new(1 << 2).unwrap().trailing_zeros(); + assert_eq!(TRAILING_ZEROS, 2); +} + +#[test] +fn test_nonzero_uint_div() { + let nz = NonZero::new(1).unwrap(); + + let x: u32 = 42u32 / nz; + assert_eq!(x, 42u32); +} + +#[test] +fn test_nonzero_uint_rem() { + let nz = NonZero::new(10).unwrap(); + + let x: u32 = 42u32 % nz; + assert_eq!(x, 2u32); +} + +#[test] +fn test_signed_nonzero_neg() { + assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); + assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); + + assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); + assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); + + assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); + assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); + + assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); + assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); + + assert_eq!((-NonZero::::new(1).unwrap()).get(), -1); + assert_eq!((-NonZero::::new(-1).unwrap()).get(), 1); +} + +#[test] +fn test_nonzero_fmt() { + let i = format!("{0}, {0:?}, {0:x}, {0:X}, {0:#x}, {0:#X}, {0:o}, {0:b}, {0:e}, {0:E}", 42); + let nz = format!( + "{0}, {0:?}, {0:x}, {0:X}, {0:#x}, {0:#X}, {0:o}, {0:b}, {0:e}, {0:E}", + NonZero::new(42).unwrap() + ); + + assert_eq!(i, nz); +} diff --git a/library/coretests/tests/num/bignum.rs b/library/coretests/tests/num/bignum.rs new file mode 100644 index 00000000000..f213fd5366c --- /dev/null +++ b/library/coretests/tests/num/bignum.rs @@ -0,0 +1,276 @@ +use core::num::bignum::Big32x40; +use core::num::bignum::tests::Big8x3 as Big; + +#[test] +#[should_panic] +fn test_from_u64_overflow() { + Big::from_u64(0x1000000); +} + +#[test] +fn test_add() { + assert_eq!(*Big::from_small(3).add(&Big::from_small(4)), Big::from_small(7)); + assert_eq!(*Big::from_small(3).add(&Big::from_small(0)), Big::from_small(3)); + assert_eq!(*Big::from_small(0).add(&Big::from_small(3)), Big::from_small(3)); + assert_eq!(*Big::from_small(3).add(&Big::from_u64(0xfffe)), Big::from_u64(0x10001)); + assert_eq!(*Big::from_u64(0xfedc).add(&Big::from_u64(0x789)), Big::from_u64(0x10665)); + assert_eq!(*Big::from_u64(0x789).add(&Big::from_u64(0xfedc)), Big::from_u64(0x10665)); +} + +#[test] +#[should_panic] +fn test_add_overflow_1() { + Big::from_small(1).add(&Big::from_u64(0xffffff)); +} + +#[test] +#[should_panic] +fn test_add_overflow_2() { + Big::from_u64(0xffffff).add(&Big::from_small(1)); +} + +#[test] +fn test_add_small() { + assert_eq!(*Big::from_small(3).add_small(4), Big::from_small(7)); + assert_eq!(*Big::from_small(3).add_small(0), Big::from_small(3)); + assert_eq!(*Big::from_small(0).add_small(3), Big::from_small(3)); + assert_eq!(*Big::from_small(7).add_small(250), Big::from_u64(257)); + assert_eq!(*Big::from_u64(0x7fff).add_small(1), Big::from_u64(0x8000)); + assert_eq!(*Big::from_u64(0x2ffe).add_small(0x35), Big::from_u64(0x3033)); + assert_eq!(*Big::from_small(0xdc).add_small(0x89), Big::from_u64(0x165)); +} + +#[test] +#[should_panic] +fn test_add_small_overflow() { + Big::from_u64(0xffffff).add_small(1); +} + +#[test] +fn test_sub() { + assert_eq!(*Big::from_small(7).sub(&Big::from_small(4)), Big::from_small(3)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x789)), Big::from_u64(0xfedc)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0xfedc)), Big::from_u64(0x789)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10664)), Big::from_small(1)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10665)), Big::from_small(0)); +} + +#[test] +#[should_panic] +fn test_sub_underflow_1() { + Big::from_u64(0x10665).sub(&Big::from_u64(0x10666)); +} + +#[test] +#[should_panic] +fn test_sub_underflow_2() { + Big::from_small(0).sub(&Big::from_u64(0x123456)); +} + +#[test] +fn test_mul_small() { + assert_eq!(*Big::from_small(7).mul_small(5), Big::from_small(35)); + assert_eq!(*Big::from_small(0xff).mul_small(0xff), Big::from_u64(0xfe01)); + assert_eq!(*Big::from_u64(0xffffff / 13).mul_small(13), Big::from_u64(0xffffff)); +} + +#[test] +#[should_panic] +fn test_mul_small_overflow() { + Big::from_u64(0x800000).mul_small(2); +} + +#[test] +fn test_mul_pow2() { + assert_eq!(*Big::from_small(0x7).mul_pow2(4), Big::from_small(0x70)); + assert_eq!(*Big::from_small(0xff).mul_pow2(1), Big::from_u64(0x1fe)); + assert_eq!(*Big::from_small(0xff).mul_pow2(12), Big::from_u64(0xff000)); + assert_eq!(*Big::from_small(0x1).mul_pow2(23), Big::from_u64(0x800000)); + assert_eq!(*Big::from_u64(0x123).mul_pow2(0), Big::from_u64(0x123)); + assert_eq!(*Big::from_u64(0x123).mul_pow2(7), Big::from_u64(0x9180)); + assert_eq!(*Big::from_u64(0x123).mul_pow2(15), Big::from_u64(0x918000)); + assert_eq!(*Big::from_small(0).mul_pow2(23), Big::from_small(0)); +} + +#[test] +#[should_panic] +fn test_mul_pow2_overflow_1() { + Big::from_u64(0x1).mul_pow2(24); +} + +#[test] +#[should_panic] +fn test_mul_pow2_overflow_2() { + Big::from_u64(0x123).mul_pow2(16); +} + +#[test] +fn test_mul_pow5() { + assert_eq!(*Big::from_small(42).mul_pow5(0), Big::from_small(42)); + assert_eq!(*Big::from_small(1).mul_pow5(2), Big::from_small(25)); + assert_eq!(*Big::from_small(1).mul_pow5(4), Big::from_u64(25 * 25)); + assert_eq!(*Big::from_small(4).mul_pow5(3), Big::from_u64(500)); + assert_eq!(*Big::from_small(140).mul_pow5(2), Big::from_u64(25 * 140)); + assert_eq!(*Big::from_small(25).mul_pow5(1), Big::from_small(125)); + assert_eq!(*Big::from_small(125).mul_pow5(7), Big::from_u64(9765625)); + assert_eq!(*Big::from_small(0).mul_pow5(127), Big::from_small(0)); +} + +#[test] +#[should_panic] +fn test_mul_pow5_overflow_1() { + Big::from_small(1).mul_pow5(12); +} + +#[test] +#[should_panic] +fn test_mul_pow5_overflow_2() { + Big::from_small(230).mul_pow5(8); +} + +#[test] +fn test_mul_digits() { + assert_eq!(*Big::from_small(3).mul_digits(&[5]), Big::from_small(15)); + assert_eq!(*Big::from_small(0xff).mul_digits(&[0xff]), Big::from_u64(0xfe01)); + assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), Big::from_u64(0x4edc2)); + assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), Big::from_u64(0x7530c3)); + assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), Big::from_u64(0x3ae13e)); + assert_eq!(*Big::from_u64(0xffffff / 13).mul_digits(&[13]), Big::from_u64(0xffffff)); + assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), Big::from_u64(0xffffff)); +} + +#[test] +#[should_panic] +fn test_mul_digits_overflow_1() { + Big::from_u64(0x800000).mul_digits(&[2]); +} + +#[test] +#[should_panic] +fn test_mul_digits_overflow_2() { + Big::from_u64(0x1000).mul_digits(&[0, 0x10]); +} + +#[test] +fn test_div_rem_small() { + let as_val = |(q, r): (&mut Big, u8)| (q.clone(), r); + assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), (Big::from_small(17), 0)); + assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), (Big::from_small(15), 15)); + assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), (Big::from_small(0), 3)); + assert_eq!( + as_val(Big::from_u64(0xffffff).div_rem_small(123)), + (Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8) + ); + assert_eq!( + as_val(Big::from_u64(0x10000).div_rem_small(123)), + (Big::from_u64(0x10000 / 123), (0x10000u64 % 123) as u8) + ); +} + +#[test] +fn test_div_rem() { + fn div_rem(n: u64, d: u64) -> (Big, Big) { + let mut q = Big::from_small(42); + let mut r = Big::from_small(42); + Big::from_u64(n).div_rem(&Big::from_u64(d), &mut q, &mut r); + (q, r) + } + assert_eq!(div_rem(1, 1), (Big::from_small(1), Big::from_small(0))); + assert_eq!(div_rem(4, 3), (Big::from_small(1), Big::from_small(1))); + assert_eq!(div_rem(1, 7), (Big::from_small(0), Big::from_small(1))); + assert_eq!(div_rem(45, 9), (Big::from_small(5), Big::from_small(0))); + assert_eq!(div_rem(103, 9), (Big::from_small(11), Big::from_small(4))); + assert_eq!(div_rem(123456, 77), (Big::from_u64(1603), Big::from_small(25))); + assert_eq!(div_rem(0xffff, 1), (Big::from_u64(0xffff), Big::from_small(0))); + assert_eq!(div_rem(0xeeee, 0xffff), (Big::from_small(0), Big::from_u64(0xeeee))); + assert_eq!(div_rem(2_000_000, 2), (Big::from_u64(1_000_000), Big::from_u64(0))); +} + +#[test] +fn test_is_zero() { + assert!(Big::from_small(0).is_zero()); + assert!(!Big::from_small(3).is_zero()); + assert!(!Big::from_u64(0x123).is_zero()); + assert!(!Big::from_u64(0xffffff).sub(&Big::from_u64(0xfffffe)).is_zero()); + assert!(Big::from_u64(0xffffff).sub(&Big::from_u64(0xffffff)).is_zero()); +} + +#[test] +fn test_get_bit() { + let x = Big::from_small(0b1101); + assert_eq!(x.get_bit(0), 1); + assert_eq!(x.get_bit(1), 0); + assert_eq!(x.get_bit(2), 1); + assert_eq!(x.get_bit(3), 1); + let y = Big::from_u64(1 << 15); + assert_eq!(y.get_bit(14), 0); + assert_eq!(y.get_bit(15), 1); + assert_eq!(y.get_bit(16), 0); +} + +#[test] +#[should_panic] +fn test_get_bit_out_of_range() { + Big::from_small(42).get_bit(24); +} + +#[test] +fn test_bit_length() { + for i in 0..8 * 3 { + // 010000...000 + assert_eq!(Big::from_small(1).mul_pow2(i).bit_length(), i + 1); + } + for i in 1..8 * 3 - 1 { + // 010000...001 + assert_eq!(Big::from_small(1).mul_pow2(i).add(&Big::from_small(1)).bit_length(), i + 1); + // 110000...000 + assert_eq!(Big::from_small(3).mul_pow2(i).bit_length(), i + 2); + } + assert_eq!(Big::from_small(0).bit_length(), 0); + assert_eq!(Big::from_small(1).bit_length(), 1); + assert_eq!(Big::from_small(5).bit_length(), 3); + assert_eq!(Big::from_small(0x18).bit_length(), 5); + assert_eq!(Big::from_u64(0x4073).bit_length(), 15); + assert_eq!(Big::from_u64(0xffffff).bit_length(), 24); +} + +#[test] +fn test_bit_length_32x40() { + for i in 0..32 * 40 { + // 010000...000 + assert_eq!(Big32x40::from_small(1).mul_pow2(i).bit_length(), i + 1); + } + for i in 1..32 * 40 - 1 { + // 010000...001 + assert_eq!( + Big32x40::from_small(1).mul_pow2(i).add(&Big32x40::from_small(1)).bit_length(), + i + 1 + ); + // 110000...000 + assert_eq!(Big32x40::from_small(3).mul_pow2(i).bit_length(), i + 2); + } + assert_eq!(Big32x40::from_small(0).bit_length(), 0); + assert_eq!(Big32x40::from_small(1).bit_length(), 1); + assert_eq!(Big32x40::from_small(5).bit_length(), 3); + assert_eq!(Big32x40::from_small(0x18).bit_length(), 5); + assert_eq!(Big32x40::from_u64(0x4073).bit_length(), 15); + assert_eq!(Big32x40::from_u64(0xffffff).bit_length(), 24); + assert_eq!(Big32x40::from_u64(0xffffffffffffffff).bit_length(), 64); +} + +#[test] +fn test_ord() { + assert!(Big::from_u64(0) < Big::from_u64(0xffffff)); + assert!(Big::from_u64(0x102) < Big::from_u64(0x201)); +} + +#[test] +fn test_fmt() { + assert_eq!(format!("{:?}", Big::from_u64(0)), "0x0"); + assert_eq!(format!("{:?}", Big::from_u64(0x1)), "0x1"); + assert_eq!(format!("{:?}", Big::from_u64(0x12)), "0x12"); + assert_eq!(format!("{:?}", Big::from_u64(0x123)), "0x1_23"); + assert_eq!(format!("{:?}", Big::from_u64(0x1234)), "0x12_34"); + assert_eq!(format!("{:?}", Big::from_u64(0x12345)), "0x1_23_45"); + assert_eq!(format!("{:?}", Big::from_u64(0x123456)), "0x12_34_56"); +} diff --git a/library/coretests/tests/num/const_from.rs b/library/coretests/tests/num/const_from.rs new file mode 100644 index 00000000000..fa58e771879 --- /dev/null +++ b/library/coretests/tests/num/const_from.rs @@ -0,0 +1,27 @@ +/* FIXME(#110395) +#[test] +fn from() { + use core::convert::TryFrom; + use core::num::TryFromIntError; + + // From + const FROM: i64 = i64::from(1i32); + assert_eq!(FROM, 1i64); + + // From int to float + const FROM_F64: f64 = f64::from(42u8); + assert_eq!(FROM_F64, 42f64); + + // Upper bounded + const U8_FROM_U16: Result = u8::try_from(1u16); + assert_eq!(U8_FROM_U16, Ok(1u8)); + + // Both bounded + const I8_FROM_I16: Result = i8::try_from(1i16); + assert_eq!(I8_FROM_I16, Ok(1i8)); + + // Lower bounded + const I16_FROM_U16: Result = i16::try_from(1u16); + assert_eq!(I16_FROM_U16, Ok(1i16)); +} +*/ diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs new file mode 100644 index 00000000000..7a9587a18d0 --- /dev/null +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -0,0 +1,33 @@ +use core::num::dec2flt::float::RawFloat; + +#[test] +fn test_f32_integer_decode() { + assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); + assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); + assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); + assert_eq!(0f32.integer_decode(), (0, -150, 1)); + assert_eq!((-0f32).integer_decode(), (0, -150, -1)); + assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1)); + assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (12582912, 105)); +} + +#[test] +fn test_f64_integer_decode() { + assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); + assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); + assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); + assert_eq!(0f64.integer_decode(), (0, -1075, 1)); + assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); + assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1)); + assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (6755399441055744, 972)); +} diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs new file mode 100644 index 00000000000..f71bbb7c7a3 --- /dev/null +++ b/library/coretests/tests/num/dec2flt/lemire.rs @@ -0,0 +1,53 @@ +use core::num::dec2flt::lemire::compute_float; + +fn compute_float32(q: i64, w: u64) -> (i32, u64) { + let fp = compute_float::(q, w); + (fp.e, fp.f) +} + +fn compute_float64(q: i64, w: u64) -> (i32, u64) { + let fp = compute_float::(q, w); + (fp.e, fp.f) +} + +#[test] +fn compute_float_f32_rounding() { + // These test near-halfway cases for single-precision floats. + assert_eq!(compute_float32(0, 16777216), (151, 0)); + assert_eq!(compute_float32(0, 16777217), (151, 0)); + assert_eq!(compute_float32(0, 16777218), (151, 1)); + assert_eq!(compute_float32(0, 16777219), (151, 2)); + assert_eq!(compute_float32(0, 16777220), (151, 2)); + + // These are examples of the above tests, with + // digits from the exponent shifted to the mantissa. + assert_eq!(compute_float32(-10, 167772160000000000), (151, 0)); + assert_eq!(compute_float32(-10, 167772170000000000), (151, 0)); + assert_eq!(compute_float32(-10, 167772180000000000), (151, 1)); + // Let's check the lines to see if anything is different in table... + assert_eq!(compute_float32(-10, 167772190000000000), (151, 2)); + assert_eq!(compute_float32(-10, 167772200000000000), (151, 2)); +} + +#[test] +fn compute_float_f64_rounding() { + // These test near-halfway cases for double-precision floats. + assert_eq!(compute_float64(0, 9007199254740992), (1076, 0)); + assert_eq!(compute_float64(0, 9007199254740993), (1076, 0)); + assert_eq!(compute_float64(0, 9007199254740994), (1076, 1)); + assert_eq!(compute_float64(0, 9007199254740995), (1076, 2)); + assert_eq!(compute_float64(0, 9007199254740996), (1076, 2)); + assert_eq!(compute_float64(0, 18014398509481984), (1077, 0)); + assert_eq!(compute_float64(0, 18014398509481986), (1077, 0)); + assert_eq!(compute_float64(0, 18014398509481988), (1077, 1)); + assert_eq!(compute_float64(0, 18014398509481990), (1077, 2)); + assert_eq!(compute_float64(0, 18014398509481992), (1077, 2)); + + // These are examples of the above tests, with + // digits from the exponent shifted to the mantissa. + assert_eq!(compute_float64(-3, 9007199254740992000), (1076, 0)); + assert_eq!(compute_float64(-3, 9007199254740993000), (1076, 0)); + assert_eq!(compute_float64(-3, 9007199254740994000), (1076, 1)); + assert_eq!(compute_float64(-3, 9007199254740995000), (1076, 2)); + assert_eq!(compute_float64(-3, 9007199254740996000), (1076, 2)); +} diff --git a/library/coretests/tests/num/dec2flt/mod.rs b/library/coretests/tests/num/dec2flt/mod.rs new file mode 100644 index 00000000000..874e0ec7093 --- /dev/null +++ b/library/coretests/tests/num/dec2flt/mod.rs @@ -0,0 +1,129 @@ +#![allow(overflowing_literals)] + +mod float; +mod lemire; +mod parse; + +// Take a float literal, turn it into a string in various ways (that are all trusted +// to be correct) and see if those strings are parsed back to the value of the literal. +// Requires a *polymorphic literal*, i.e., one that can serve as f64 as well as f32. +macro_rules! test_literal { + ($x: expr) => {{ + let x32: f32 = $x; + let x64: f64 = $x; + let inputs = &[stringify!($x).into(), format!("{:?}", x64), format!("{:e}", x64)]; + for input in inputs { + assert_eq!(input.parse(), Ok(x64)); + assert_eq!(input.parse(), Ok(x32)); + let neg_input = format!("-{input}"); + assert_eq!(neg_input.parse(), Ok(-x64)); + assert_eq!(neg_input.parse(), Ok(-x32)); + } + }}; +} + +#[test] +fn ordinary() { + test_literal!(1.0); + test_literal!(3e-5); + test_literal!(0.1); + test_literal!(12345.); + test_literal!(0.9999999); + test_literal!(2.2250738585072014e-308); +} + +#[test] +fn special_code_paths() { + test_literal!(36893488147419103229.0); // 2^65 - 3, triggers half-to-even with even significand + test_literal!(101e-33); // Triggers the tricky underflow case in AlgorithmM (for f32) + test_literal!(1e23); // Triggers AlgorithmR + test_literal!(2075e23); // Triggers another path through AlgorithmR + test_literal!(8713e-23); // ... and yet another. +} + +#[test] +fn large() { + test_literal!(1e300); + test_literal!(123456789.34567e250); + test_literal!(943794359898089732078308743689303290943794359843568973207830874368930329.); +} + +#[test] +fn subnormals() { + test_literal!(5e-324); + test_literal!(91e-324); + test_literal!(1e-322); + test_literal!(13245643e-320); + test_literal!(2.22507385851e-308); + test_literal!(2.1e-308); + test_literal!(4.9406564584124654e-324); +} + +#[test] +fn infinity() { + test_literal!(1e400); + test_literal!(1e309); + test_literal!(2e308); + test_literal!(1.7976931348624e308); +} + +#[test] +fn zero() { + test_literal!(0.0); + test_literal!(1e-325); + test_literal!(1e-326); + test_literal!(1e-500); +} + +#[test] +fn fast_path_correct() { + // This number triggers the fast path and is handled incorrectly when compiling on + // x86 without SSE2 (i.e., using the x87 FPU stack). + test_literal!(1.448997445238699); +} + +#[test] +fn lonely_dot() { + assert!(".".parse::().is_err()); + assert!(".".parse::().is_err()); +} + +#[test] +fn exponentiated_dot() { + assert!(".e0".parse::().is_err()); + assert!(".e0".parse::().is_err()); +} + +#[test] +fn lonely_sign() { + assert!("+".parse::().is_err()); + assert!("-".parse::().is_err()); +} + +#[test] +fn whitespace() { + assert!(" 1.0".parse::().is_err()); + assert!("1.0 ".parse::().is_err()); +} + +#[test] +fn nan() { + assert!("NaN".parse::().unwrap().is_nan()); + assert!("NaN".parse::().unwrap().is_nan()); +} + +#[test] +fn inf() { + assert_eq!("inf".parse(), Ok(f64::INFINITY)); + assert_eq!("-inf".parse(), Ok(f64::NEG_INFINITY)); + assert_eq!("inf".parse(), Ok(f32::INFINITY)); + assert_eq!("-inf".parse(), Ok(f32::NEG_INFINITY)); +} + +#[test] +fn massive_exponent() { + let max = i64::MAX; + assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY)); + assert_eq!(format!("1e-{max}000").parse(), Ok(0.0)); + assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY)); +} diff --git a/library/coretests/tests/num/dec2flt/parse.rs b/library/coretests/tests/num/dec2flt/parse.rs new file mode 100644 index 00000000000..4a5d24ba7d5 --- /dev/null +++ b/library/coretests/tests/num/dec2flt/parse.rs @@ -0,0 +1,177 @@ +use core::num::dec2flt::number::Number; +use core::num::dec2flt::parse::parse_number; +use core::num::dec2flt::{dec2flt, pfe_invalid}; + +fn new_number(e: i64, m: u64) -> Number { + Number { exponent: e, mantissa: m, negative: false, many_digits: false } +} + +#[test] +fn missing_pieces() { + let permutations = &[".e", "1e", "e4", "e", ".12e", "321.e", "32.12e+", "12.32e-"]; + for &s in permutations { + assert_eq!(dec2flt::(s), Err(pfe_invalid())); + } +} + +#[test] +fn invalid_chars() { + let invalid = "r,?(&input) == error, "did not reject invalid {:?}", input); + } + } + } +} + +fn parse_positive(s: &[u8]) -> Option { + parse_number(s) +} + +#[test] +fn valid() { + assert_eq!(parse_positive(b"123.456e789"), Some(new_number(786, 123456))); + assert_eq!(parse_positive(b"123.456e+789"), Some(new_number(786, 123456))); + assert_eq!(parse_positive(b"123.456e-789"), Some(new_number(-792, 123456))); + assert_eq!(parse_positive(b".050"), Some(new_number(-3, 50))); + assert_eq!(parse_positive(b"999"), Some(new_number(0, 999))); + assert_eq!(parse_positive(b"1.e300"), Some(new_number(300, 1))); + assert_eq!(parse_positive(b".1e300"), Some(new_number(299, 1))); + assert_eq!(parse_positive(b"101e-33"), Some(new_number(-33, 101))); + let zeros = "0".repeat(25); + let s = format!("1.5e{zeros}"); + assert_eq!(parse_positive(s.as_bytes()), Some(new_number(-1, 15))); +} + +macro_rules! assert_float_result_bits_eq { + ($bits:literal, $ty:ty, $str:literal) => {{ + let p = dec2flt::<$ty>($str); + assert_eq!(p.map(|x| x.to_bits()), Ok($bits)); + }}; +} + +#[test] +fn issue31109() { + // Regression test for #31109. + // Ensure the test produces a valid float with the expected bit pattern. + assert_float_result_bits_eq!( + 0x3fd5555555555555, + f64, + "0.3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333" + ); +} + +#[test] +fn issue31407() { + // Regression test for #31407. + // Ensure the test produces a valid float with the expected bit pattern. + assert_float_result_bits_eq!( + 0x1752a64e34ba0d3, + f64, + "1234567890123456789012345678901234567890e-340" + ); + assert_float_result_bits_eq!( + 0xfffffffffffff, + f64, + "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718749999999999999999999999999999999999999e-308" + ); + assert_float_result_bits_eq!( + 0x10000000000000, + f64, + "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308" + ); + assert_float_result_bits_eq!( + 0x10000000000000, + f64, + "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000222507385850720138309023271733240406421921598046233183055332741688720443481391819585428315901251102056406733973103581100515243416155346010885601238537771882113077799353200233047961014744258363607192156504694250373420837525080665061665815894872049117996859163964850063590877011830487479978088775374994945158045160505091539985658247081864511353793580499211598108576605199243335211435239014879569960959128889160299264151106346631339366347758651302937176204732563178148566435087212282863764204484681140761391147706280168985324411002416144742161856716615054015428508471675290190316132277889672970737312333408698898317506783884692609277397797285865965494109136909540613646756870239867831529068098461721092462539672851562500000000000000001" + ); + assert_float_result_bits_eq!( + 0x7fefffffffffffff, + f64, + "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999" + ); + assert_float_result_bits_eq!(0x0, f64, "2.47032822920623272e-324"); + assert_float_result_bits_eq!( + 0x8000000, + f64, + "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316" + ); + assert_float_result_bits_eq!( + 0x10000, + f64, + "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875E-319" + ); + assert_float_result_bits_eq!( + 0x800000000100, + f64, + "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125E-310" + ); + assert_float_result_bits_eq!( + 0x10800, + f64, + "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875E-319" + ); + assert_float_result_bits_eq!( + 0x0, + f64, + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999e-324" + ); + assert_float_result_bits_eq!( + 0x0, + f64, + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125e-324" + ); + assert_float_result_bits_eq!( + 0x1, + f64, + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324" + ); + assert_float_result_bits_eq!( + 0x1, + f64, + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324" + ); + assert_float_result_bits_eq!( + 0x2, + f64, + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324" + ); + assert_float_result_bits_eq!( + 0x2, + f64, + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324" + ); + assert_float_result_bits_eq!( + 0x6c9a143590c14, + f64, + "94393431193180696942841837085033647913224148539854e-358" + ); + assert_float_result_bits_eq!( + 0x7802665fd9600, + f64, + "104308485241983990666713401708072175773165034278685682646111762292409330928739751702404658197872319129036519947435319418387839758990478549477777586673075945844895981012024387992135617064532141489278815239849108105951619997829153633535314849999674266169258928940692239684771590065027025835804863585454872499320500023126142553932654370362024104462255244034053203998964360882487378334860197725139151265590832887433736189468858614521708567646743455601905935595381852723723645799866672558576993978025033590728687206296379801363024094048327273913079612469982585674824156000783167963081616214710691759864332339239688734656548790656486646106983450809073750535624894296242072010195710276073042036425579852459556183541199012652571123898996574563824424330960027873516082763671875e-1075" + ); +} + +#[test] +fn many_digits() { + // Check large numbers of digits to ensure we have cases where significant + // digits (above Decimal::MAX_DIGITS) occurs. + assert_float_result_bits_eq!( + 0x7ffffe, + f32, + "1.175494140627517859246175898662808184331245864732796240031385942718174675986064769972472277004271745681762695312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-38" + ); + assert_float_result_bits_eq!( + 0x7ffffe, + f32, + "1.175494140627517859246175898662808184331245864732796240031385942718174675986064769972472277004271745681762695312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-38" + ); +} diff --git a/library/coretests/tests/num/float_iter_sum_identity.rs b/library/coretests/tests/num/float_iter_sum_identity.rs new file mode 100644 index 00000000000..6d3224522a8 --- /dev/null +++ b/library/coretests/tests/num/float_iter_sum_identity.rs @@ -0,0 +1,27 @@ +#[test] +fn f32_ref() { + let x: f32 = -0.0; + let still_x: f32 = [x].iter().sum(); + assert_eq!(1. / x, 1. / still_x) +} + +#[test] +fn f32_own() { + let x: f32 = -0.0; + let still_x: f32 = [x].into_iter().sum(); + assert_eq!(1. / x, 1. / still_x) +} + +#[test] +fn f64_ref() { + let x: f64 = -0.0; + let still_x: f64 = [x].iter().sum(); + assert_eq!(1. / x, 1. / still_x) +} + +#[test] +fn f64_own() { + let x: f64 = -0.0; + let still_x: f64 = [x].into_iter().sum(); + assert_eq!(1. / x, 1. / still_x) +} diff --git a/library/coretests/tests/num/flt2dec/estimator.rs b/library/coretests/tests/num/flt2dec/estimator.rs new file mode 100644 index 00000000000..da203b5f362 --- /dev/null +++ b/library/coretests/tests/num/flt2dec/estimator.rs @@ -0,0 +1,62 @@ +use core::num::flt2dec::estimator::*; + +#[test] +fn test_estimate_scaling_factor() { + macro_rules! assert_almost_eq { + ($actual:expr, $expected:expr) => {{ + let actual = $actual; + let expected = $expected; + println!( + "{} - {} = {} - {} = {}", + stringify!($expected), + stringify!($actual), + expected, + actual, + expected - actual + ); + assert!( + expected == actual || expected == actual + 1, + "expected {}, actual {}", + expected, + actual + ); + }}; + } + + assert_almost_eq!(estimate_scaling_factor(1, 0), 0); + assert_almost_eq!(estimate_scaling_factor(2, 0), 1); + assert_almost_eq!(estimate_scaling_factor(10, 0), 1); + assert_almost_eq!(estimate_scaling_factor(11, 0), 2); + assert_almost_eq!(estimate_scaling_factor(100, 0), 2); + assert_almost_eq!(estimate_scaling_factor(101, 0), 3); + assert_almost_eq!(estimate_scaling_factor(10000000000000000000, 0), 19); + assert_almost_eq!(estimate_scaling_factor(10000000000000000001, 0), 20); + + // 1/2^20 = 0.00000095367... + assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000, -20), -6); + assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000 + 1, -20), -5); + assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000, -20), -5); + assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000 + 1, -20), -4); + assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000, -20), -4); + assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000 + 1, -20), -3); + assert_almost_eq!(estimate_scaling_factor(1048575, -20), 0); + assert_almost_eq!(estimate_scaling_factor(1048576, -20), 0); + assert_almost_eq!(estimate_scaling_factor(1048577, -20), 1); + assert_almost_eq!(estimate_scaling_factor(10485759999999999999, -20), 13); + assert_almost_eq!(estimate_scaling_factor(10485760000000000000, -20), 13); + assert_almost_eq!(estimate_scaling_factor(10485760000000000001, -20), 14); + + // extreme values: + // 2^-1074 = 4.94065... * 10^-324 + // (2^53-1) * 2^971 = 1.79763... * 10^308 + assert_almost_eq!(estimate_scaling_factor(1, -1074), -323); + assert_almost_eq!(estimate_scaling_factor(0x1fffffffffffff, 971), 309); + + // Miri is too slow + let step = if cfg!(miri) { 37 } else { 1 }; + + for i in (-1074..972).step_by(step) { + let expected = super::ldexp_f64(1.0, i).log10().ceil(); + assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16); + } +} diff --git a/library/coretests/tests/num/flt2dec/mod.rs b/library/coretests/tests/num/flt2dec/mod.rs new file mode 100644 index 00000000000..3d825224813 --- /dev/null +++ b/library/coretests/tests/num/flt2dec/mod.rs @@ -0,0 +1,1168 @@ +use core::num::flt2dec::{ + DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, Sign, decode, round_up, to_exact_exp_str, + to_exact_fixed_str, to_shortest_exp_str, to_shortest_str, +}; +use core::num::fmt::{Formatted, Part}; +use std::mem::MaybeUninit; +use std::{fmt, str}; + +mod estimator; +mod strategy { + mod dragon; + mod grisu; +} +mod random; + +pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { + FullDecoded::Finite(decoded) => decoded, + full_decoded => panic!("expected finite, got {full_decoded:?} instead"), + } +} + +macro_rules! check_shortest { + ($f:ident($v:expr) => $buf:expr, $exp:expr) => ( + check_shortest!($f($v) => $buf, $exp; + "shortest mismatch for v={v}: actual {actual:?}, expected {expected:?}", + v = stringify!($v)) + ); + + ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr) => ( + check_shortest!($f{$($k: $v),+} => $buf, $exp; + "shortest mismatch for {v:?}: actual {actual:?}, expected {expected:?}", + v = Decoded { $($k: $v),+ }) + ); + + ($f:ident($v:expr) => $buf:expr, $exp:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ + let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; + let (buf, k) = $f(&decode_finite($v), &mut buf); + assert!((buf, k) == ($buf, $exp), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), + expected = (str::from_utf8($buf).unwrap(), $exp), + $($key = $val),*); + }); + + ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr; + $fmt:expr, $($key:ident = $val:expr),*) => ({ + let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; + let (buf, k) = $f(&Decoded { $($k: $v),+ }, &mut buf); + assert!((buf, k) == ($buf, $exp), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), + expected = (str::from_utf8($buf).unwrap(), $exp), + $($key = $val),*); + }) +} + +macro_rules! try_exact { + ($f:ident($decoded:expr) => $buf:expr, $expected:expr, $expectedk:expr; + $fmt:expr, $($key:ident = $val:expr),*) => ({ + let (buf, k) = $f($decoded, &mut $buf[..$expected.len()], i16::MIN); + assert!((buf, k) == ($expected, $expectedk), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), + expected = (str::from_utf8($expected).unwrap(), $expectedk), + $($key = $val),*); + }) +} + +macro_rules! try_fixed { + ($f:ident($decoded:expr) => $buf:expr, $request:expr, $expected:expr, $expectedk:expr; + $fmt:expr, $($key:ident = $val:expr),*) => ({ + let (buf, k) = $f($decoded, &mut $buf[..], $request); + assert!((buf, k) == ($expected, $expectedk), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), + expected = (str::from_utf8($expected).unwrap(), $expectedk), + $($key = $val),*); + }) +} + +fn ldexp_f32(a: f32, b: i32) -> f32 { + ldexp_f64(a as f64, b) as f32 +} + +fn ldexp_f64(a: f64, b: i32) -> f64 { + extern "C" { + fn ldexp(x: f64, n: i32) -> f64; + } + // SAFETY: assuming a correct `ldexp` has been supplied, the given arguments cannot possibly + // cause undefined behavior + unsafe { ldexp(a, b) } +} + +fn check_exact(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16) +where + T: DecodableFloat, + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), +{ + // use a large enough buffer + let mut buf = [MaybeUninit::new(b'_'); 1024]; + let mut expected_ = [b'_'; 1024]; + + let decoded = decode_finite(v); + let cut = expected.iter().position(|&c| c == b' '); + + // check significant digits + for i in 1..cut.unwrap_or(expected.len() - 1) { + expected_[..i].copy_from_slice(&expected[..i]); + let mut expectedk_ = expectedk; + if expected[i] >= b'5' { + // check if this is a rounding-to-even case. + // we avoid rounding ...x5000... (with infinite zeroes) to ...(x+1) when x is even. + if !(i + 1 < expected.len() + && expected[i - 1] & 1 == 0 + && expected[i] == b'5' + && expected[i + 1] == b' ') + { + // if this returns true, expected_[..i] is all `9`s and being rounded up. + // we should always return `100..00` (`i` digits) instead, since that's + // what we can came up with `i` digits anyway. `round_up` assumes that + // the adjustment to the length is done by caller, which we simply ignore. + if let Some(_) = round_up(&mut expected_[..i]) { + expectedk_ += 1; + } + } + } + + try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk_; + "exact sigdigit mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = i); + try_fixed!(f(&decoded) => &mut buf, expectedk_ - i as i16, &expected_[..i], expectedk_; + "fixed sigdigit mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = i); + } + + // check exact rounding for zero- and negative-width cases + let start; + if expected[0] > b'5' { + try_fixed!(f(&decoded) => &mut buf, expectedk, b"1", expectedk + 1; + "zero-width rounding-up mismatch for v={v}: \ + actual {actual:?}, expected {expected:?}", + v = vstr); + start = 1; + } else { + start = 0; + } + for i in start..-10 { + try_fixed!(f(&decoded) => &mut buf, expectedk - i, b"", expectedk; + "rounding-down mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = -i); + } + + // check infinite zero digits + if let Some(cut) = cut { + for i in cut..expected.len() - 1 { + expected_[..cut].copy_from_slice(&expected[..cut]); + for c in &mut expected_[cut..i] { + *c = b'0'; + } + + try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk; + "exact infzero mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = i); + try_fixed!(f(&decoded) => &mut buf, expectedk - i as i16, &expected_[..i], expectedk; + "fixed infzero mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = i); + } + } +} + +trait TestableFloat: DecodableFloat + fmt::Display { + /// Returns `x * 2^exp`. Almost same to `std::{f32,f64}::ldexp`. + /// This is used for testing. + fn ldexpi(f: i64, exp: isize) -> Self; +} + +impl TestableFloat for f32 { + fn ldexpi(f: i64, exp: isize) -> Self { + f as Self * (exp as Self).exp2() + } +} + +impl TestableFloat for f64 { + fn ldexpi(f: i64, exp: isize) -> Self { + f as Self * (exp as Self).exp2() + } +} + +fn check_exact_one(mut f: F, x: i64, e: isize, tstr: &str, expected: &[u8], expectedk: i16) +where + T: TestableFloat, + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), +{ + // use a large enough buffer + let mut buf = [MaybeUninit::new(b'_'); 1024]; + let v: T = TestableFloat::ldexpi(x, e); + let decoded = decode_finite(v); + + try_exact!(f(&decoded) => &mut buf, &expected, expectedk; + "exact mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}", + x = x, e = e, t = tstr); + try_fixed!(f(&decoded) => &mut buf, expectedk - expected.len() as i16, &expected, expectedk; + "fixed mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}", + x = x, e = e, t = tstr); +} + +macro_rules! check_exact { + ($f:ident($v:expr) => $buf:expr, $exp:expr) => { + check_exact(|d, b, k| $f(d, b, k), $v, stringify!($v), $buf, $exp) + }; +} + +macro_rules! check_exact_one { + ($f:ident($x:expr, $e:expr; $t:ty) => $buf:expr, $exp:expr) => { + check_exact_one::<_, $t>(|d, b, k| $f(d, b, k), $x, $e, stringify!($t), $buf, $exp) + }; +} + +// in the following comments, three numbers are spaced by 1 ulp apart, +// and the second one is being formatted. +// +// some tests are derived from [1]. +// +// [1] Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion +// ftp://ftp.ee.lbl.gov/testbase-report.ps.Z + +pub fn f32_shortest_sanity_test(mut f: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + // 0.0999999940395355224609375 + // 0.100000001490116119384765625 + // 0.10000000894069671630859375 + check_shortest!(f(0.1f32) => b"1", 0); + + // 0.333333313465118408203125 + // 0.3333333432674407958984375 (1/3 in the default rounding) + // 0.33333337306976318359375 + check_shortest!(f(1.0f32/3.0) => b"33333334", 0); + + // 10^1 * 0.31415917873382568359375 + // 10^1 * 0.31415920257568359375 + // 10^1 * 0.31415922641754150390625 + check_shortest!(f(3.141592f32) => b"3141592", 1); + + // 10^18 * 0.31415916243714048 + // 10^18 * 0.314159196796878848 + // 10^18 * 0.314159231156617216 + check_shortest!(f(3.141592e17f32) => b"3141592", 18); + + // regression test for decoders + // 10^8 * 0.3355443 + // 10^8 * 0.33554432 + // 10^8 * 0.33554436 + check_shortest!(f(ldexp_f32(1.0, 25)) => b"33554432", 8); + + // 10^39 * 0.340282326356119256160033759537265639424 + // 10^39 * 0.34028234663852885981170418348451692544 + // 10^39 * 0.340282366920938463463374607431768211456 + check_shortest!(f(f32::MAX) => b"34028235", 39); + + // 10^-37 * 0.1175494210692441075487029444849287348827... + // 10^-37 * 0.1175494350822287507968736537222245677818... + // 10^-37 * 0.1175494490952133940450443629595204006810... + check_shortest!(f(f32::MIN_POSITIVE) => b"11754944", -37); + + // 10^-44 * 0 + // 10^-44 * 0.1401298464324817070923729583289916131280... + // 10^-44 * 0.2802596928649634141847459166579832262560... + let minf32 = ldexp_f32(1.0, -149); + check_shortest!(f(minf32) => b"1", -44); +} + +pub fn f32_exact_sanity_test(mut f: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), +{ + let minf32 = ldexp_f32(1.0, -149); + + check_exact!(f(0.1f32) => b"100000001490116119384765625 ", 0); + check_exact!(f(0.5f32) => b"5 ", 0); + check_exact!(f(1.0f32/3.0) => b"3333333432674407958984375 ", 0); + check_exact!(f(3.141592f32) => b"31415920257568359375 ", 1); + check_exact!(f(3.141592e17f32) => b"314159196796878848 ", 18); + check_exact!(f(f32::MAX) => b"34028234663852885981170418348451692544 ", 39); + check_exact!(f(f32::MIN_POSITIVE) => b"1175494350822287507968736537222245677818", -37); + check_exact!(f(minf32) => b"1401298464324817070923729583289916131280", -44); + + // [1], Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP + check_exact_one!(f(12676506, -102; f32) => b"2", -23); + check_exact_one!(f(12676506, -103; f32) => b"12", -23); + check_exact_one!(f(15445013, 86; f32) => b"119", 34); + check_exact_one!(f(13734123, -138; f32) => b"3941", -34); + check_exact_one!(f(12428269, -130; f32) => b"91308", -32); + check_exact_one!(f(15334037, -146; f32) => b"171900", -36); + check_exact_one!(f(11518287, -41; f32) => b"5237910", -5); + check_exact_one!(f(12584953, -145; f32) => b"28216440", -36); + check_exact_one!(f(15961084, -125; f32) => b"375243281", -30); + check_exact_one!(f(14915817, -146; f32) => b"1672120916", -36); + check_exact_one!(f(10845484, -102; f32) => b"21388945814", -23); + check_exact_one!(f(16431059, -61; f32) => b"712583594561", -11); + + // [1], Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP + check_exact_one!(f(16093626, 69; f32) => b"1", 29); + check_exact_one!(f( 9983778, 25; f32) => b"34", 15); + check_exact_one!(f(12745034, 104; f32) => b"259", 39); + check_exact_one!(f(12706553, 72; f32) => b"6001", 29); + check_exact_one!(f(11005028, 45; f32) => b"38721", 21); + check_exact_one!(f(15059547, 71; f32) => b"355584", 29); + check_exact_one!(f(16015691, -99; f32) => b"2526831", -22); + check_exact_one!(f( 8667859, 56; f32) => b"62458507", 24); + check_exact_one!(f(14855922, -82; f32) => b"307213267", -17); + check_exact_one!(f(14855922, -83; f32) => b"1536066333", -17); + check_exact_one!(f(10144164, -110; f32) => b"78147796834", -26); + check_exact_one!(f(13248074, 95; f32) => b"524810279937", 36); +} + +pub fn f64_shortest_sanity_test(mut f: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + // 0.0999999999999999777955395074968691915273... + // 0.1000000000000000055511151231257827021181... + // 0.1000000000000000333066907387546962127089... + check_shortest!(f(0.1f64) => b"1", 0); + + // this example is explicitly mentioned in the paper. + // 10^3 * 0.0999999999999999857891452847979962825775... + // 10^3 * 0.1 (exact) + // 10^3 * 0.1000000000000000142108547152020037174224... + check_shortest!(f(100.0f64) => b"1", 3); + + // 0.3333333333333332593184650249895639717578... + // 0.3333333333333333148296162562473909929394... (1/3 in the default rounding) + // 0.3333333333333333703407674875052180141210... + check_shortest!(f(1.0f64/3.0) => b"3333333333333333", 0); + + // explicit test case for equally closest representations. + // Dragon has its own tie-breaking rule; Grisu should fall back. + // 10^1 * 0.1000007629394531027955395074968691915273... + // 10^1 * 0.100000762939453125 (exact) + // 10^1 * 0.1000007629394531472044604925031308084726... + check_shortest!(f(1.00000762939453125f64) => b"10000076293945313", 1); + + // 10^1 * 0.3141591999999999718085064159822650253772... + // 10^1 * 0.3141592000000000162174274009885266423225... + // 10^1 * 0.3141592000000000606263483859947882592678... + check_shortest!(f(3.141592f64) => b"3141592", 1); + + // 10^18 * 0.314159199999999936 + // 10^18 * 0.3141592 (exact) + // 10^18 * 0.314159200000000064 + check_shortest!(f(3.141592e17f64) => b"3141592", 18); + + // regression test for decoders + // 10^20 * 0.18446744073709549568 + // 10^20 * 0.18446744073709551616 + // 10^20 * 0.18446744073709555712 + check_shortest!(f(ldexp_f64(1.0, 64)) => b"18446744073709552", 20); + + // pathological case: high = 10^23 (exact). tie breaking should always prefer that. + // 10^24 * 0.099999999999999974834176 + // 10^24 * 0.099999999999999991611392 + // 10^24 * 0.100000000000000008388608 + check_shortest!(f(1.0e23f64) => b"1", 24); + + // 10^309 * 0.1797693134862315508561243283845062402343... + // 10^309 * 0.1797693134862315708145274237317043567980... + // 10^309 * 0.1797693134862315907729305190789024733617... + check_shortest!(f(f64::MAX) => b"17976931348623157", 309); + + // 10^-307 * 0.2225073858507200889024586876085859887650... + // 10^-307 * 0.2225073858507201383090232717332404064219... + // 10^-307 * 0.2225073858507201877155878558578948240788... + check_shortest!(f(f64::MIN_POSITIVE) => b"22250738585072014", -307); + + // 10^-323 * 0 + // 10^-323 * 0.4940656458412465441765687928682213723650... + // 10^-323 * 0.9881312916824930883531375857364427447301... + let minf64 = ldexp_f64(1.0, -1074); + check_shortest!(f(minf64) => b"5", -323); +} + +pub fn f64_exact_sanity_test(mut f: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), +{ + let minf64 = ldexp_f64(1.0, -1074); + + check_exact!(f(0.1f64) => b"1000000000000000055511151231257827021181", 0); + check_exact!(f(0.45f64) => b"4500000000000000111022302462515654042363", 0); + check_exact!(f(0.5f64) => b"5 ", 0); + check_exact!(f(0.95f64) => b"9499999999999999555910790149937383830547", 0); + check_exact!(f(100.0f64) => b"1 ", 3); + check_exact!(f(999.5f64) => b"9995000000000000000000000000000000000000", 3); + check_exact!(f(1.0f64/3.0) => b"3333333333333333148296162562473909929394", 0); + check_exact!(f(3.141592f64) => b"3141592000000000162174274009885266423225", 1); + check_exact!(f(3.141592e17f64) => b"3141592 ", 18); + check_exact!(f(1.0e23f64) => b"99999999999999991611392 ", 23); + check_exact!(f(f64::MAX) => b"1797693134862315708145274237317043567980", 309); + check_exact!(f(f64::MIN_POSITIVE) => b"2225073858507201383090232717332404064219", -307); + check_exact!(f(minf64) => b"4940656458412465441765687928682213723650\ + 5980261432476442558568250067550727020875\ + 1865299836361635992379796564695445717730\ + 9266567103559397963987747960107818781263\ + 0071319031140452784581716784898210368871\ + 8636056998730723050006387409153564984387\ + 3124733972731696151400317153853980741262\ + 3856559117102665855668676818703956031062\ + 4931945271591492455329305456544401127480\ + 1297099995419319894090804165633245247571\ + 4786901472678015935523861155013480352649\ + 3472019379026810710749170333222684475333\ + 5720832431936092382893458368060106011506\ + 1698097530783422773183292479049825247307\ + 7637592724787465608477820373446969953364\ + 7017972677717585125660551199131504891101\ + 4510378627381672509558373897335989936648\ + 0994116420570263709027924276754456522908\ + 7538682506419718265533447265625 ", -323); + + // [1], Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP + check_exact_one!(f(8511030020275656, -342; f64) => b"9", -87); + check_exact_one!(f(5201988407066741, -824; f64) => b"46", -232); + check_exact_one!(f(6406892948269899, 237; f64) => b"141", 88); + check_exact_one!(f(8431154198732492, 72; f64) => b"3981", 38); + check_exact_one!(f(6475049196144587, 99; f64) => b"41040", 46); + check_exact_one!(f(8274307542972842, 726; f64) => b"292084", 235); + check_exact_one!(f(5381065484265332, -456; f64) => b"2891946", -121); + check_exact_one!(f(6761728585499734, -1057; f64) => b"43787718", -302); + check_exact_one!(f(7976538478610756, 376; f64) => b"122770163", 130); + check_exact_one!(f(5982403858958067, 377; f64) => b"1841552452", 130); + check_exact_one!(f(5536995190630837, 93; f64) => b"54835744350", 44); + check_exact_one!(f(7225450889282194, 710; f64) => b"389190181146", 230); + check_exact_one!(f(7225450889282194, 709; f64) => b"1945950905732", 230); + check_exact_one!(f(8703372741147379, 117; f64) => b"14460958381605", 52); + check_exact_one!(f(8944262675275217, -1001; f64) => b"417367747458531", -285); + check_exact_one!(f(7459803696087692, -707; f64) => b"1107950772878888", -196); + check_exact_one!(f(6080469016670379, -381; f64) => b"12345501366327440", -98); + check_exact_one!(f(8385515147034757, 721; f64) => b"925031711960365024", 233); + check_exact_one!(f(7514216811389786, -828; f64) => b"4198047150284889840", -233); + check_exact_one!(f(8397297803260511, -345; f64) => b"11716315319786511046", -87); + check_exact_one!(f(6733459239310543, 202; f64) => b"432810072844612493629", 77); + check_exact_one!(f(8091450587292794, -473; f64) => b"3317710118160031081518", -126); + + // [1], Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP + check_exact_one!(f(6567258882077402, 952; f64) => b"3", 303); + check_exact_one!(f(6712731423444934, 535; f64) => b"76", 177); + check_exact_one!(f(6712731423444934, 534; f64) => b"378", 177); + check_exact_one!(f(5298405411573037, -957; f64) => b"4350", -272); + check_exact_one!(f(5137311167659507, -144; f64) => b"23037", -27); + check_exact_one!(f(6722280709661868, 363; f64) => b"126301", 126); + check_exact_one!(f(5344436398034927, -169; f64) => b"7142211", -35); + check_exact_one!(f(8369123604277281, -853; f64) => b"13934574", -240); + check_exact_one!(f(8995822108487663, -780; f64) => b"141463449", -218); + check_exact_one!(f(8942832835564782, -383; f64) => b"4539277920", -99); + check_exact_one!(f(8942832835564782, -384; f64) => b"22696389598", -99); + check_exact_one!(f(8942832835564782, -385; f64) => b"113481947988", -99); + check_exact_one!(f(6965949469487146, -249; f64) => b"7700366561890", -59); + check_exact_one!(f(6965949469487146, -250; f64) => b"38501832809448", -59); + check_exact_one!(f(6965949469487146, -251; f64) => b"192509164047238", -59); + check_exact_one!(f(7487252720986826, 548; f64) => b"6898586531774201", 181); + check_exact_one!(f(5592117679628511, 164; f64) => b"13076622631878654", 66); + check_exact_one!(f(8887055249355788, 665; f64) => b"136052020756121240", 217); + check_exact_one!(f(6994187472632449, 690; f64) => b"3592810217475959676", 224); + check_exact_one!(f(8797576579012143, 588; f64) => b"89125197712484551899", 193); + check_exact_one!(f(7363326733505337, 272; f64) => b"558769757362301140950", 98); + check_exact_one!(f(8549497411294502, -448; f64) => b"1176257830728540379990", -118); +} + +pub fn more_shortest_sanity_test(mut f: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, + exp: 0, inclusive: true} => b"1", 18); + check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, + exp: 0, inclusive: false} => b"99999999999999999", 17); +} + +fn to_string_with_parts(mut f: F) -> String +where + F: for<'a> FnMut(&'a mut [MaybeUninit], &'a mut [MaybeUninit>]) -> Formatted<'a>, +{ + let mut buf = [MaybeUninit::new(0); 1024]; + let mut parts = [MaybeUninit::new(Part::Zero(0)); 16]; + let formatted = f(&mut buf, &mut parts); + let mut ret = vec![0; formatted.len()]; + assert_eq!(formatted.write(&mut ret), Some(ret.len())); + String::from_utf8(ret).unwrap() +} + +pub fn to_shortest_str_test(mut f_: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + use core::num::flt2dec::Sign::*; + + fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String + where + T: DecodableFloat, + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), + { + to_string_with_parts(|buf, parts| { + to_shortest_str(|d, b| f(d, b), v, sign, frac_digits, buf, parts) + }) + } + + let f = &mut f_; + + assert_eq!(to_string(f, 0.0, Minus, 0), "0"); + assert_eq!(to_string(f, 0.0, Minus, 0), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); + assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); + assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); + assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); + assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); + + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 0), "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); + assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3.14"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3.14"); + assert_eq!(to_string(f, 3.14, Minus, 1), "3.14"); + assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); + + assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750"); + + assert_eq!(to_string(f, 1.9971e20, Minus, 0), "199710000000000000000"); + assert_eq!(to_string(f, 1.9971e20, Minus, 1), "199710000000000000000.0"); + assert_eq!(to_string(f, 1.9971e20, Minus, 8), "199710000000000000000.00000000"); + + assert_eq!(to_string(f, f32::MAX, Minus, 0), format!("34028235{:0>31}", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 1), format!("34028235{:0>31}.0", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 8), format!("34028235{:0>31}.00000000", "")); + + let minf32 = ldexp_f32(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, 0), format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 45), format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 46), format!("0.{:0>44}10", "")); + + assert_eq!(to_string(f, f64::MAX, Minus, 0), format!("17976931348623157{:0>292}", "")); + assert_eq!(to_string(f, f64::MAX, Minus, 1), format!("17976931348623157{:0>292}.0", "")); + assert_eq!(to_string(f, f64::MAX, Minus, 8), format!("17976931348623157{:0>292}.00000000", "")); + + let minf64 = ldexp_f64(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, 0), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 324), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 325), format!("0.{:0>323}50", "")); + + if cfg!(miri) { + // Miri is too slow + return; + } + + // very large output + assert_eq!(to_string(f, 1.1, Minus, 80000), format!("1.1{:0>79999}", "")); +} + +pub fn to_shortest_exp_str_test(mut f_: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + use core::num::flt2dec::Sign::*; + + fn to_string(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: bool) -> String + where + T: DecodableFloat, + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), + { + to_string_with_parts(|buf, parts| { + to_shortest_exp_str(|d, b| f(d, b), v, sign, exp_bounds, upper, buf, parts) + }) + } + + let f = &mut f_; + + assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); + assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, (-4, 16), false), "+0"); + assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "-0"); + assert_eq!(to_string(f, 0.0, Minus, (0, 0), true), "0E0"); + assert_eq!(to_string(f, 0.0, Minus, (0, 0), false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, (5, 9), false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, (0, 0), true), "-0E0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (5, 9), false), "-0e0"); + + assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), false), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, (-4, 16), true), "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, (5, 9), true), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, (5, 9), true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, (-4, 16), false), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, (-4, 16), false), "+3.14"); + assert_eq!(to_string(f, -3.14, Minus, (-4, 16), false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlus, (-4, 16), false), "-3.14"); + assert_eq!(to_string(f, 3.14, Minus, (0, 0), true), "3.14E0"); + assert_eq!(to_string(f, 3.14, Minus, (0, 0), false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, (5, 9), false), "+3.14e0"); + assert_eq!(to_string(f, -3.14, Minus, (0, 0), true), "-3.14E0"); + assert_eq!(to_string(f, -3.14, Minus, (0, 0), false), "-3.14e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, (5, 9), false), "-3.14e0"); + + assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); + assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); + assert_eq!(to_string(f, 0.1, MinusPlus, (-4, 16), false), "+0.1"); + assert_eq!(to_string(f, -0.1, Minus, (-4, 16), false), "-0.1"); + assert_eq!(to_string(f, -0.1, MinusPlus, (-4, 16), false), "-0.1"); + assert_eq!(to_string(f, 0.1, Minus, (0, 0), true), "1E-1"); + assert_eq!(to_string(f, 0.1, Minus, (0, 0), false), "1e-1"); + assert_eq!(to_string(f, 0.1, MinusPlus, (5, 9), false), "+1e-1"); + assert_eq!(to_string(f, -0.1, Minus, (0, 0), true), "-1E-1"); + assert_eq!(to_string(f, -0.1, Minus, (0, 0), false), "-1e-1"); + assert_eq!(to_string(f, -0.1, MinusPlus, (5, 9), false), "-1e-1"); + + assert_eq!(to_string(f, 7.5e-11, Minus, (-4, 16), false), "7.5e-11"); + assert_eq!(to_string(f, 7.5e-11, Minus, (-11, 10), false), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, (-10, 11), false), "7.5e-11"); + + assert_eq!(to_string(f, 1.9971e20, Minus, (-4, 16), false), "1.9971e20"); + assert_eq!(to_string(f, 1.9971e20, Minus, (-20, 21), false), "199710000000000000000"); + assert_eq!(to_string(f, 1.9971e20, Minus, (-21, 20), false), "1.9971e20"); + + // the true value of 1.0e23f64 is less than 10^23, but that shouldn't matter here + assert_eq!(to_string(f, 1.0e23, Minus, (22, 23), false), "1e23"); + assert_eq!(to_string(f, 1.0e23, Minus, (23, 24), false), "100000000000000000000000"); + assert_eq!(to_string(f, 1.0e23, Minus, (24, 25), false), "1e23"); + + assert_eq!(to_string(f, f32::MAX, Minus, (-4, 16), false), "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", "")); + + let minf32 = ldexp_f32(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, (-4, 16), false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", "")); + + assert_eq!(to_string(f, f64::MAX, Minus, (-4, 16), false), "1.7976931348623157e308"); + assert_eq!( + to_string(f, f64::MAX, Minus, (-308, 309), false), + format!("17976931348623157{:0>292}", "") + ); + assert_eq!(to_string(f, f64::MAX, Minus, (-309, 308), false), "1.7976931348623157e308"); + + let minf64 = ldexp_f64(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, (-4, 16), false), "5e-324"); + assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324"); + + assert_eq!(to_string(f, 1.1, Minus, (i16::MIN, i16::MAX), false), "1.1"); +} + +pub fn to_exact_exp_str_test(mut f_: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), +{ + use core::num::flt2dec::Sign::*; + + fn to_string(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) -> String + where + T: DecodableFloat, + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), + { + to_string_with_parts(|buf, parts| { + to_exact_exp_str(|d, b, l| f(d, b, l), v, sign, ndigits, upper, buf, parts) + }) + } + + let f = &mut f_; + + assert_eq!(to_string(f, 0.0, Minus, 1, true), "0E0"); + assert_eq!(to_string(f, 0.0, Minus, 1, false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1, false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, 1, true), "-0E0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 1, false), "-0e0"); + assert_eq!(to_string(f, 0.0, Minus, 2, true), "0.0E0"); + assert_eq!(to_string(f, 0.0, Minus, 2, false), "0.0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 2, false), "+0.0e0"); + assert_eq!(to_string(f, -0.0, Minus, 8, false), "-0.0000000e0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8, false), "-0.0000000e0"); + + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, false), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, true), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 1, true), "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, false), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, true), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, true), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, false), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, true), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64, true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 1, true), "3E0"); + assert_eq!(to_string(f, 3.14, Minus, 1, false), "3e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 1, false), "+3e0"); + assert_eq!(to_string(f, -3.14, Minus, 2, true), "-3.1E0"); + assert_eq!(to_string(f, -3.14, Minus, 2, false), "-3.1e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 2, false), "-3.1e0"); + assert_eq!(to_string(f, 3.14, Minus, 3, true), "3.14E0"); + assert_eq!(to_string(f, 3.14, Minus, 3, false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3, false), "+3.14e0"); + assert_eq!(to_string(f, -3.14, Minus, 4, true), "-3.140E0"); + assert_eq!(to_string(f, -3.14, Minus, 4, false), "-3.140e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 4, false), "-3.140e0"); + + assert_eq!(to_string(f, 0.195, Minus, 1, false), "2e-1"); + assert_eq!(to_string(f, 0.195, Minus, 1, true), "2E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 1, true), "+2E-1"); + assert_eq!(to_string(f, -0.195, Minus, 2, false), "-2.0e-1"); + assert_eq!(to_string(f, -0.195, Minus, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, 0.195, Minus, 3, false), "1.95e-1"); + assert_eq!(to_string(f, 0.195, Minus, 3, true), "1.95E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+1.95E-1"); + assert_eq!(to_string(f, -0.195, Minus, 4, false), "-1.950e-1"); + assert_eq!(to_string(f, -0.195, Minus, 4, true), "-1.950E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 4, true), "-1.950E-1"); + + assert_eq!(to_string(f, 9.5, Minus, 1, false), "1e1"); + assert_eq!(to_string(f, 9.5, Minus, 2, false), "9.5e0"); + assert_eq!(to_string(f, 9.5, Minus, 3, false), "9.50e0"); + assert_eq!(to_string(f, 9.5, Minus, 30, false), "9.50000000000000000000000000000e0"); + + assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "1e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 2, false), "1.0e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 15, false), "1.00000000000000e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 16, false), "1.000000000000000e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 17, false), "1.0000000000000001e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 18, false), "1.00000000000000009e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 19, false), "1.000000000000000091e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 20, false), "1.0000000000000000906e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 21, false), "1.00000000000000009060e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 22, false), "1.000000000000000090597e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 23, false), "1.0000000000000000905970e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 24, false), "1.00000000000000009059697e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 25, false), "1.000000000000000090596966e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 26, false), "1.0000000000000000905969664e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 27, false), "1.00000000000000009059696640e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 30, false), "1.00000000000000009059696640000e25"); + + assert_eq!(to_string(f, 1.0e-6, Minus, 1, false), "1e-6"); + assert_eq!(to_string(f, 1.0e-6, Minus, 2, false), "1.0e-6"); + assert_eq!(to_string(f, 1.0e-6, Minus, 16, false), "1.000000000000000e-6"); + assert_eq!(to_string(f, 1.0e-6, Minus, 17, false), "9.9999999999999995e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 18, false), "9.99999999999999955e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 19, false), "9.999999999999999547e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 20, false), "9.9999999999999995475e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 30, false), "9.99999999999999954748111825886e-7"); + assert_eq!( + to_string(f, 1.0e-6, Minus, 40, false), + "9.999999999999999547481118258862586856139e-7" + ); + assert_eq!( + to_string(f, 1.0e-6, Minus, 50, false), + "9.9999999999999995474811182588625868561393872369081e-7" + ); + assert_eq!( + to_string(f, 1.0e-6, Minus, 60, false), + "9.99999999999999954748111825886258685613938723690807819366455e-7" + ); + assert_eq!( + to_string(f, 1.0e-6, Minus, 70, false), + "9.999999999999999547481118258862586856139387236908078193664550781250000e-7" + ); + + assert_eq!(to_string(f, f32::MAX, Minus, 1, false), "3e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "3.4e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 4, false), "3.403e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 8, false), "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 16, false), "3.402823466385289e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 32, false), "3.4028234663852885981170418348452e38"); + assert_eq!( + to_string(f, f32::MAX, Minus, 64, false), + "3.402823466385288598117041834845169254400000000000000000000000000e38" + ); + + let minf32 = ldexp_f32(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, 1, false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, 2, false), "1.4e-45"); + assert_eq!(to_string(f, minf32, Minus, 4, false), "1.401e-45"); + assert_eq!(to_string(f, minf32, Minus, 8, false), "1.4012985e-45"); + assert_eq!(to_string(f, minf32, Minus, 16, false), "1.401298464324817e-45"); + assert_eq!(to_string(f, minf32, Minus, 32, false), "1.4012984643248170709237295832899e-45"); + assert_eq!( + to_string(f, minf32, Minus, 64, false), + "1.401298464324817070923729583289916131280261941876515771757068284e-45" + ); + assert_eq!( + to_string(f, minf32, Minus, 128, false), + "1.401298464324817070923729583289916131280261941876515771757068283\ + 8897910826858606014866381883621215820312500000000000000000000000e-45" + ); + + if cfg!(miri) { + // Miri is too slow + return; + } + + assert_eq!(to_string(f, f64::MAX, Minus, 1, false), "2e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 2, false), "1.8e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 4, false), "1.798e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 8, false), "1.7976931e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 16, false), "1.797693134862316e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 32, false), "1.7976931348623157081452742373170e308"); + assert_eq!( + to_string(f, f64::MAX, Minus, 64, false), + "1.797693134862315708145274237317043567980705675258449965989174768e308" + ); + assert_eq!( + to_string(f, f64::MAX, Minus, 128, false), + "1.797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432133e308" + ); + assert_eq!( + to_string(f, f64::MAX, Minus, 256, false), + "1.797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432132\ + 6889464182768467546703537516986049910576551282076245490090389328\ + 9440758685084551339423045832369032229481658085593321233482747978e308" + ); + assert_eq!( + to_string(f, f64::MAX, Minus, 512, false), + "1.797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432132\ + 6889464182768467546703537516986049910576551282076245490090389328\ + 9440758685084551339423045832369032229481658085593321233482747978\ + 2620414472316873817718091929988125040402618412485836800000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000e308" + ); + + // okay, this is becoming tough. fortunately for us, this is almost the worst case. + let minf64 = ldexp_f64(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, 1, false), "5e-324"); + assert_eq!(to_string(f, minf64, Minus, 2, false), "4.9e-324"); + assert_eq!(to_string(f, minf64, Minus, 4, false), "4.941e-324"); + assert_eq!(to_string(f, minf64, Minus, 8, false), "4.9406565e-324"); + assert_eq!(to_string(f, minf64, Minus, 16, false), "4.940656458412465e-324"); + assert_eq!(to_string(f, minf64, Minus, 32, false), "4.9406564584124654417656879286822e-324"); + assert_eq!( + to_string(f, minf64, Minus, 64, false), + "4.940656458412465441765687928682213723650598026143247644255856825e-324" + ); + assert_eq!( + to_string(f, minf64, Minus, 128, false), + "4.940656458412465441765687928682213723650598026143247644255856825\ + 0067550727020875186529983636163599237979656469544571773092665671e-324" + ); + assert_eq!( + to_string(f, minf64, Minus, 256, false), + "4.940656458412465441765687928682213723650598026143247644255856825\ + 0067550727020875186529983636163599237979656469544571773092665671\ + 0355939796398774796010781878126300713190311404527845817167848982\ + 1036887186360569987307230500063874091535649843873124733972731696e-324" + ); + assert_eq!( + to_string(f, minf64, Minus, 512, false), + "4.940656458412465441765687928682213723650598026143247644255856825\ + 0067550727020875186529983636163599237979656469544571773092665671\ + 0355939796398774796010781878126300713190311404527845817167848982\ + 1036887186360569987307230500063874091535649843873124733972731696\ + 1514003171538539807412623856559117102665855668676818703956031062\ + 4931945271591492455329305456544401127480129709999541931989409080\ + 4165633245247571478690147267801593552386115501348035264934720193\ + 7902681071074917033322268447533357208324319360923828934583680601e-324" + ); + assert_eq!( + to_string(f, minf64, Minus, 1024, false), + "4.940656458412465441765687928682213723650598026143247644255856825\ + 0067550727020875186529983636163599237979656469544571773092665671\ + 0355939796398774796010781878126300713190311404527845817167848982\ + 1036887186360569987307230500063874091535649843873124733972731696\ + 1514003171538539807412623856559117102665855668676818703956031062\ + 4931945271591492455329305456544401127480129709999541931989409080\ + 4165633245247571478690147267801593552386115501348035264934720193\ + 7902681071074917033322268447533357208324319360923828934583680601\ + 0601150616980975307834227731832924790498252473077637592724787465\ + 6084778203734469699533647017972677717585125660551199131504891101\ + 4510378627381672509558373897335989936648099411642057026370902792\ + 4276754456522908753868250641971826553344726562500000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000e-324" + ); + + // very large output + assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>79999}e0", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("1.{:0>79999}e1", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>79999}e0", "")); + assert_eq!( + to_string(f, 1.0e-1, Minus, 80000, false), + format!( + "1.000000000000000055511151231257827021181583404541015625{:0>79945}\ + e-1", + "" + ) + ); + assert_eq!( + to_string(f, 1.0e-20, Minus, 80000, false), + format!( + "9.999999999999999451532714542095716517295037027873924471077157760\ + 66783064379706047475337982177734375{:0>79901}e-21", + "" + ) + ); +} + +pub fn to_exact_fixed_str_test(mut f_: F) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), +{ + use core::num::flt2dec::Sign::*; + + fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String + where + T: DecodableFloat, + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), + { + to_string_with_parts(|buf, parts| { + to_exact_fixed_str(|d, b, l| f(d, b, l), v, sign, frac_digits, buf, parts) + }) + } + + let f = &mut f_; + + assert_eq!(to_string(f, 0.0, Minus, 0), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); + assert_eq!(to_string(f, -0.0, Minus, 0), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0"); + assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); + assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000"); + + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 64), "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 0), "3"); + assert_eq!(to_string(f, 3.14, Minus, 0), "3"); + assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); + assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3"); + assert_eq!(to_string(f, 3.14, Minus, 1), "3.1"); + assert_eq!(to_string(f, 3.14, Minus, 2), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); + + assert_eq!(to_string(f, 0.195, Minus, 0), "0"); + assert_eq!(to_string(f, 0.195, MinusPlus, 0), "+0"); + assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); + assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); + assert_eq!(to_string(f, -0.195, MinusPlus, 0), "-0"); + assert_eq!(to_string(f, 0.195, Minus, 1), "0.2"); + assert_eq!(to_string(f, 0.195, Minus, 2), "0.20"); + assert_eq!(to_string(f, 0.195, MinusPlus, 4), "+0.1950"); + assert_eq!(to_string(f, -0.195, Minus, 5), "-0.19500"); + assert_eq!(to_string(f, -0.195, Minus, 6), "-0.195000"); + assert_eq!(to_string(f, -0.195, MinusPlus, 8), "-0.19500000"); + + assert_eq!(to_string(f, 999.5, Minus, 0), "1000"); + assert_eq!(to_string(f, 999.5, Minus, 1), "999.5"); + assert_eq!(to_string(f, 999.5, Minus, 2), "999.50"); + assert_eq!(to_string(f, 999.5, Minus, 3), "999.500"); + assert_eq!(to_string(f, 999.5, Minus, 30), "999.500000000000000000000000000000"); + + assert_eq!(to_string(f, 0.5, Minus, 0), "0"); + assert_eq!(to_string(f, 0.5, Minus, 1), "0.5"); + assert_eq!(to_string(f, 0.5, Minus, 2), "0.50"); + assert_eq!(to_string(f, 0.5, Minus, 3), "0.500"); + + assert_eq!(to_string(f, 0.95, Minus, 0), "1"); + assert_eq!(to_string(f, 0.95, Minus, 1), "0.9"); // because it really is less than 0.95 + assert_eq!(to_string(f, 0.95, Minus, 2), "0.95"); + assert_eq!(to_string(f, 0.95, Minus, 3), "0.950"); + assert_eq!(to_string(f, 0.95, Minus, 10), "0.9500000000"); + assert_eq!(to_string(f, 0.95, Minus, 30), "0.949999999999999955591079014994"); + + assert_eq!(to_string(f, 0.095, Minus, 0), "0"); + assert_eq!(to_string(f, 0.095, Minus, 1), "0.1"); + assert_eq!(to_string(f, 0.095, Minus, 2), "0.10"); + assert_eq!(to_string(f, 0.095, Minus, 3), "0.095"); + assert_eq!(to_string(f, 0.095, Minus, 4), "0.0950"); + assert_eq!(to_string(f, 0.095, Minus, 10), "0.0950000000"); + assert_eq!(to_string(f, 0.095, Minus, 30), "0.095000000000000001110223024625"); + + assert_eq!(to_string(f, 0.0095, Minus, 0), "0"); + assert_eq!(to_string(f, 0.0095, Minus, 1), "0.0"); + assert_eq!(to_string(f, 0.0095, Minus, 2), "0.01"); + assert_eq!(to_string(f, 0.0095, Minus, 3), "0.009"); // really is less than 0.0095 + assert_eq!(to_string(f, 0.0095, Minus, 4), "0.0095"); + assert_eq!(to_string(f, 0.0095, Minus, 5), "0.00950"); + assert_eq!(to_string(f, 0.0095, Minus, 10), "0.0095000000"); + assert_eq!(to_string(f, 0.0095, Minus, 30), "0.009499999999999999764077607267"); + + assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0"); + assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000"); + assert_eq!(to_string(f, 7.5e-11, Minus, 10), "0.0000000001"); + assert_eq!(to_string(f, 7.5e-11, Minus, 11), "0.00000000007"); // ditto + assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750"); + assert_eq!(to_string(f, 7.5e-11, Minus, 20), "0.00000000007500000000"); + assert_eq!(to_string(f, 7.5e-11, Minus, 30), "0.000000000074999999999999999501"); + + assert_eq!(to_string(f, 1.0e25, Minus, 0), "10000000000000000905969664"); + assert_eq!(to_string(f, 1.0e25, Minus, 1), "10000000000000000905969664.0"); + assert_eq!(to_string(f, 1.0e25, Minus, 3), "10000000000000000905969664.000"); + + assert_eq!(to_string(f, 1.0e-6, Minus, 0), "0"); + assert_eq!(to_string(f, 1.0e-6, Minus, 3), "0.000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 6), "0.000001"); + assert_eq!(to_string(f, 1.0e-6, Minus, 9), "0.000001000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 12), "0.000001000000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 22), "0.0000010000000000000000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 23), "0.00000099999999999999995"); + assert_eq!(to_string(f, 1.0e-6, Minus, 24), "0.000000999999999999999955"); + assert_eq!(to_string(f, 1.0e-6, Minus, 25), "0.0000009999999999999999547"); + assert_eq!(to_string(f, 1.0e-6, Minus, 35), "0.00000099999999999999995474811182589"); + assert_eq!(to_string(f, 1.0e-6, Minus, 45), "0.000000999999999999999954748111825886258685614"); + assert_eq!( + to_string(f, 1.0e-6, Minus, 55), + "0.0000009999999999999999547481118258862586856139387236908" + ); + assert_eq!( + to_string(f, 1.0e-6, Minus, 65), + "0.00000099999999999999995474811182588625868561393872369080781936646" + ); + assert_eq!( + to_string(f, 1.0e-6, Minus, 75), + "0.000000999999999999999954748111825886258685613938723690807819366455078125000" + ); + + assert_eq!(to_string(f, f32::MAX, Minus, 0), "340282346638528859811704183484516925440"); + assert_eq!(to_string(f, f32::MAX, Minus, 1), "340282346638528859811704183484516925440.0"); + assert_eq!(to_string(f, f32::MAX, Minus, 2), "340282346638528859811704183484516925440.00"); + + if cfg!(miri) { + // Miri is too slow + return; + } + + let minf32 = ldexp_f32(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, 0), "0"); + assert_eq!(to_string(f, minf32, Minus, 1), "0.0"); + assert_eq!(to_string(f, minf32, Minus, 2), "0.00"); + assert_eq!(to_string(f, minf32, Minus, 4), "0.0000"); + assert_eq!(to_string(f, minf32, Minus, 8), "0.00000000"); + assert_eq!(to_string(f, minf32, Minus, 16), "0.0000000000000000"); + assert_eq!(to_string(f, minf32, Minus, 32), "0.00000000000000000000000000000000"); + assert_eq!( + to_string(f, minf32, Minus, 64), + "0.0000000000000000000000000000000000000000000014012984643248170709" + ); + assert_eq!( + to_string(f, minf32, Minus, 128), + "0.0000000000000000000000000000000000000000000014012984643248170709\ + 2372958328991613128026194187651577175706828388979108268586060149" + ); + assert_eq!( + to_string(f, minf32, Minus, 256), + "0.0000000000000000000000000000000000000000000014012984643248170709\ + 2372958328991613128026194187651577175706828388979108268586060148\ + 6638188362121582031250000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000" + ); + + assert_eq!( + to_string(f, f64::MAX, Minus, 0), + "1797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432132\ + 6889464182768467546703537516986049910576551282076245490090389328\ + 9440758685084551339423045832369032229481658085593321233482747978\ + 26204144723168738177180919299881250404026184124858368" + ); + assert_eq!( + to_string(f, f64::MAX, Minus, 10), + "1797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432132\ + 6889464182768467546703537516986049910576551282076245490090389328\ + 9440758685084551339423045832369032229481658085593321233482747978\ + 26204144723168738177180919299881250404026184124858368.0000000000" + ); + + let minf64 = ldexp_f64(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, 0), "0"); + assert_eq!(to_string(f, minf64, Minus, 1), "0.0"); + assert_eq!(to_string(f, minf64, Minus, 10), "0.0000000000"); + assert_eq!( + to_string(f, minf64, Minus, 100), + "0.0000000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000" + ); + assert_eq!( + to_string(f, minf64, Minus, 1000), + "0.0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0004940656458412465441765687928682213723650598026143247644255856\ + 8250067550727020875186529983636163599237979656469544571773092665\ + 6710355939796398774796010781878126300713190311404527845817167848\ + 9821036887186360569987307230500063874091535649843873124733972731\ + 6961514003171538539807412623856559117102665855668676818703956031\ + 0624931945271591492455329305456544401127480129709999541931989409\ + 0804165633245247571478690147267801593552386115501348035264934720\ + 1937902681071074917033322268447533357208324319360923828934583680\ + 6010601150616980975307834227731832924790498252473077637592724787\ + 4656084778203734469699533647017972677717585125660551199131504891\ + 1014510378627381672509558373897335989937" + ); + + // very large output + assert_eq!(to_string(f, 0.0, Minus, 80000), format!("0.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 80000), format!("10.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 80000), format!("1.{:0>80000}", "")); + assert_eq!( + to_string(f, 1.0e-1, Minus, 80000), + format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "") + ); + assert_eq!( + to_string(f, 1.0e-20, Minus, 80000), + format!( + "0.0000000000000000000099999999999999994515327145420957165172950370\ + 2787392447107715776066783064379706047475337982177734375{:0>79881}", + "" + ) + ); +} diff --git a/library/coretests/tests/num/flt2dec/random.rs b/library/coretests/tests/num/flt2dec/random.rs new file mode 100644 index 00000000000..90042ae03bf --- /dev/null +++ b/library/coretests/tests/num/flt2dec/random.rs @@ -0,0 +1,191 @@ +#![cfg(not(target_arch = "wasm32"))] + +use core::num::flt2dec::strategy::grisu::{format_exact_opt, format_shortest_opt}; +use core::num::flt2dec::{DecodableFloat, Decoded, FullDecoded, MAX_SIG_DIGITS, decode}; +use std::mem::MaybeUninit; +use std::str; + +use rand::distributions::{Distribution, Uniform}; + +pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { + FullDecoded::Finite(decoded) => decoded, + full_decoded => panic!("expected finite, got {full_decoded:?} instead"), + } +} + +fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), + V: FnMut(usize) -> Decoded, +{ + assert!(k <= 1024); + + let mut npassed = 0; // f(x) = Some(g(x)) + let mut nignored = 0; // f(x) = None + + for i in 0..n { + if (i & 0xfffff) == 0 { + println!( + "in progress, {:x}/{:x} (ignored={} passed={} failed={})", + i, + n, + nignored, + npassed, + i - nignored - npassed + ); + } + + let decoded = v(i); + let mut buf1 = [MaybeUninit::new(0); 1024]; + if let Some((buf1, e1)) = f(&decoded, &mut buf1[..k]) { + let mut buf2 = [MaybeUninit::new(0); 1024]; + let (buf2, e2) = g(&decoded, &mut buf2[..k]); + if e1 == e2 && buf1 == buf2 { + npassed += 1; + } else { + println!( + "equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", + i, + n, + decoded, + str::from_utf8(buf1).unwrap(), + e1, + str::from_utf8(buf2).unwrap(), + e2 + ); + } + } else { + nignored += 1; + } + } + println!( + "{}({}): done, ignored={} passed={} failed={}", + func, + k, + nignored, + npassed, + n - nignored - npassed + ); + assert!( + nignored + npassed == n, + "{}({}): {} out of {} values returns an incorrect value!", + func, + k, + n - nignored - npassed, + n + ); + (npassed, nignored) +} + +pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + let mut rng = crate::test_rng(); + let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000); + iterate("f32_random_equivalence_test", k, n, f, g, |_| { + let x = f32::from_bits(f32_range.sample(&mut rng)); + decode_finite(x) + }); +} + +pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + let mut rng = crate::test_rng(); + let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); + iterate("f64_random_equivalence_test", k, n, f, g, |_| { + let x = f64::from_bits(f64_range.sample(&mut rng)); + decode_finite(x) + }); +} + +pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) +where + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), +{ + // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, + // so why not simply testing all of them? + // + // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), + // but with `-C opt-level=3 -C lto` this only takes about an hour or so. + + // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e., all finite ranges + let (npassed, nignored) = + iterate("f32_exhaustive_equivalence_test", k, 0x7f7f_ffff, f, g, |i: usize| { + let x = f32::from_bits(i as u32 + 1); + decode_finite(x) + }); + assert_eq!((npassed, nignored), (2121451881, 17643158)); +} + +#[test] +fn shortest_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + // Miri is too slow + let n = if cfg!(miri) { 10 } else { 10_000 }; + + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n); + f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n); +} + +#[test] +#[ignore] // it is too expensive +fn shortest_f32_exhaustive_equivalence_test() { + // it is hard to directly test the optimality of the output, but we can at least test if + // two different algorithms agree to each other. + // + // this reports the progress and the number of f32 values returned `None`. + // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: + // `done, ignored=17643158 passed=2121451881 failed=0`. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); +} + +#[test] +#[ignore] // it is too expensive +fn shortest_f64_hard_random_equivalence_test() { + // this again probably has to use appropriate rustc flags. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 100_000_000); +} + +#[test] +fn exact_f32_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + // Miri is too slow + let n = if cfg!(miri) { 3 } else { 1_000 }; + + for k in 1..21 { + f32_random_equivalence_test( + |d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), + k, + n, + ); + } +} + +#[test] +fn exact_f64_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + // Miri is too slow + let n = if cfg!(miri) { 2 } else { 1_000 }; + + for k in 1..21 { + f64_random_equivalence_test( + |d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), + k, + n, + ); + } +} diff --git a/library/coretests/tests/num/flt2dec/strategy/dragon.rs b/library/coretests/tests/num/flt2dec/strategy/dragon.rs new file mode 100644 index 00000000000..be25fee3f6c --- /dev/null +++ b/library/coretests/tests/num/flt2dec/strategy/dragon.rs @@ -0,0 +1,64 @@ +use core::num::bignum::Big32x40 as Big; +use core::num::flt2dec::strategy::dragon::*; + +use super::super::*; + +#[test] +fn test_mul_pow10() { + let mut prevpow10 = Big::from_small(1); + for i in 1..340 { + let mut curpow10 = Big::from_small(1); + mul_pow10(&mut curpow10, i); + assert_eq!(curpow10, *prevpow10.clone().mul_small(10)); + prevpow10 = curpow10; + } +} + +#[test] +fn shortest_sanity_test() { + f64_shortest_sanity_test(format_shortest); + f32_shortest_sanity_test(format_shortest); + more_shortest_sanity_test(format_shortest); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn exact_sanity_test() { + // This test ends up running what I can only assume is some corner-ish case + // of the `exp2` library function, defined in whatever C runtime we're + // using. In VS 2013 this function apparently had a bug as this test fails + // when linked, but with VS 2015 the bug appears fixed as the test runs just + // fine. + // + // The bug seems to be a difference in return value of `exp2(-1057)`, where + // in VS 2013 it returns a double with the bit pattern 0x2 and in VS 2015 it + // returns 0x20000. + // + // For now just ignore this test entirely on MSVC as it's tested elsewhere + // anyway and we're not super interested in testing each platform's exp2 + // implementation. + if !cfg!(target_env = "msvc") { + f64_exact_sanity_test(format_exact); + } + f32_exact_sanity_test(format_exact); +} + +#[test] +fn test_to_shortest_str() { + to_shortest_str_test(format_shortest); +} + +#[test] +fn test_to_shortest_exp_str() { + to_shortest_exp_str_test(format_shortest); +} + +#[test] +fn test_to_exact_exp_str() { + to_exact_exp_str_test(format_exact); +} + +#[test] +fn test_to_exact_fixed_str() { + to_exact_fixed_str_test(format_exact); +} diff --git a/library/coretests/tests/num/flt2dec/strategy/grisu.rs b/library/coretests/tests/num/flt2dec/strategy/grisu.rs new file mode 100644 index 00000000000..9b2f0453de7 --- /dev/null +++ b/library/coretests/tests/num/flt2dec/strategy/grisu.rs @@ -0,0 +1,73 @@ +use core::num::flt2dec::strategy::grisu::*; + +use super::super::*; + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn test_cached_power() { + assert_eq!(CACHED_POW10.first().unwrap().1, CACHED_POW10_FIRST_E); + assert_eq!(CACHED_POW10.last().unwrap().1, CACHED_POW10_LAST_E); + + for e in -1137..961 { + // full range for f64 + let low = ALPHA - e - 64; + let high = GAMMA - e - 64; + let (_k, cached) = cached_power(low, high); + assert!( + low <= cached.e && cached.e <= high, + "cached_power({}, {}) = {:?} is incorrect", + low, + high, + cached + ); + } +} + +#[test] +fn test_max_pow10_no_more_than() { + let mut prevtenk = 1; + for k in 1..10 { + let tenk = prevtenk * 10; + assert_eq!(max_pow10_no_more_than(tenk - 1), (k - 1, prevtenk)); + assert_eq!(max_pow10_no_more_than(tenk), (k, tenk)); + prevtenk = tenk; + } +} + +#[test] +fn shortest_sanity_test() { + f64_shortest_sanity_test(format_shortest); + f32_shortest_sanity_test(format_shortest); + more_shortest_sanity_test(format_shortest); +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn exact_sanity_test() { + // See comments in dragon.rs's exact_sanity_test for why this test is + // ignored on MSVC + if !cfg!(target_env = "msvc") { + f64_exact_sanity_test(format_exact); + } + f32_exact_sanity_test(format_exact); +} + +#[test] +fn test_to_shortest_str() { + to_shortest_str_test(format_shortest); +} + +#[test] +fn test_to_shortest_exp_str() { + to_shortest_exp_str_test(format_shortest); +} + +#[test] +fn test_to_exact_exp_str() { + to_exact_exp_str_test(format_exact); +} + +#[test] +fn test_to_exact_fixed_str() { + to_exact_fixed_str_test(format_exact); +} diff --git a/library/coretests/tests/num/i128.rs b/library/coretests/tests/num/i128.rs new file mode 100644 index 00000000000..745fee05164 --- /dev/null +++ b/library/coretests/tests/num/i128.rs @@ -0,0 +1 @@ +int_module!(i128, u128); diff --git a/library/coretests/tests/num/i16.rs b/library/coretests/tests/num/i16.rs new file mode 100644 index 00000000000..6acb8371b87 --- /dev/null +++ b/library/coretests/tests/num/i16.rs @@ -0,0 +1 @@ +int_module!(i16, u16); diff --git a/library/coretests/tests/num/i32.rs b/library/coretests/tests/num/i32.rs new file mode 100644 index 00000000000..38d5071f71d --- /dev/null +++ b/library/coretests/tests/num/i32.rs @@ -0,0 +1,30 @@ +int_module!(i32, u32); + +#[test] +fn test_arith_operation() { + let a: isize = 10; + assert_eq!(a * (a - 1), 90); + let i32_a: isize = 10; + assert_eq!(i32_a, 10); + assert_eq!(i32_a - 10, 0); + assert_eq!(i32_a / 10, 1); + assert_eq!(i32_a - 20, -10); + assert_eq!(i32_a << 10, 10240); + assert_eq!(i32_a << 16, 655360); + assert_eq!(i32_a * 16, 160); + assert_eq!(i32_a * i32_a * i32_a, 1000); + assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); + assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); + assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); + let i32_b: isize = 0x10101010; + assert_eq!(i32_b + 1 - 1, i32_b); + assert_eq!(i32_b << 1, i32_b << 1); + assert_eq!(i32_b >> 1, i32_b >> 1); + assert_eq!(i32_b & i32_b << 1, 0); + assert_eq!(i32_b | i32_b << 1, 0x30303030); + let i32_c: isize = 0x10101010; + assert_eq!( + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3) + ); +} diff --git a/library/coretests/tests/num/i64.rs b/library/coretests/tests/num/i64.rs new file mode 100644 index 00000000000..f8dd5f9be7f --- /dev/null +++ b/library/coretests/tests/num/i64.rs @@ -0,0 +1 @@ +int_module!(i64, u64); diff --git a/library/coretests/tests/num/i8.rs b/library/coretests/tests/num/i8.rs new file mode 100644 index 00000000000..a10906618c9 --- /dev/null +++ b/library/coretests/tests/num/i8.rs @@ -0,0 +1 @@ +int_module!(i8, u8); diff --git a/library/coretests/tests/num/ieee754.rs b/library/coretests/tests/num/ieee754.rs new file mode 100644 index 00000000000..b0f6a7545aa --- /dev/null +++ b/library/coretests/tests/num/ieee754.rs @@ -0,0 +1,158 @@ +//! IEEE 754 floating point compliance tests +//! +//! To understand IEEE 754's requirements on a programming language, one must understand that the +//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any +//! one component. That means the hardware, language, and even libraries are considered part of +//! conforming floating point support in a programming environment. +//! +//! A programming language's duty, accordingly, is: +//! 1. offer access to the hardware where the hardware offers support +//! 2. provide operations that fulfill the remaining requirements of the standard +//! 3. provide the ability to write additional software that can fulfill those requirements +//! +//! This may be fulfilled in any combination that the language sees fit. However, to claim that +//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without +//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined +//! as complete support for at least one specified floating point type as an "arithmetic" and +//! "interchange" format, plus specified type conversions to "external character sequences" and +//! integer types. +//! +//! For our purposes, +//! "interchange format" => f32, f64 +//! "arithmetic format" => f32, f64, and any "soft floats" +//! "external character sequence" => str from any float +//! "integer format" => {i,u}{8,16,32,64,128} +//! +//! None of these tests are against Rust's own implementation. They are only tests against the +//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests. +//! Please consider this carefully when adding, removing, or reorganizing these tests. They are +//! here so that it is clear what tests are required by the standard and what can be changed. + +use ::core::str::FromStr; + +// IEEE 754 for many tests is applied to specific bit patterns. +// These generally are not applicable to NaN, however. +macro_rules! assert_biteq { + ($lhs:expr, $rhs:expr) => { + assert_eq!($lhs.to_bits(), $rhs.to_bits()) + }; +} + +// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts +// of the formatting infrastructure, which makes it ideal for testing here. +macro_rules! roundtrip { + ($f:expr => $t:ty) => { + ($f).to_string().parse::<$t>().unwrap() + }; +} + +macro_rules! assert_floats_roundtrip { + ($f:ident) => { + assert_biteq!(f32::$f, roundtrip!(f32::$f => f32)); + assert_biteq!(f64::$f, roundtrip!(f64::$f => f64)); + }; + ($f:expr) => { + assert_biteq!($f as f32, roundtrip!($f => f32)); + assert_biteq!($f as f64, roundtrip!($f => f64)); + } +} + +macro_rules! assert_floats_bitne { + ($lhs:ident, $rhs:ident) => { + assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits()); + assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits()); + }; + ($lhs:expr, $rhs:expr) => { + assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs)); + assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs)); + }; +} + +// We must preserve signs on all numbers. That includes zero. +// -0 and 0 are == normally, so test bit equality. +#[test] +fn preserve_signed_zero() { + assert_floats_roundtrip!(-0.0); + assert_floats_roundtrip!(0.0); + assert_floats_bitne!(0.0, -0.0); +} + +#[test] +fn preserve_signed_infinity() { + assert_floats_roundtrip!(INFINITY); + assert_floats_roundtrip!(NEG_INFINITY); + assert_floats_bitne!(INFINITY, NEG_INFINITY); +} + +#[test] +fn infinity_to_str() { + assert!(match f32::INFINITY.to_string().to_lowercase().as_str() { + "+infinity" | "infinity" => true, + "+inf" | "inf" => true, + _ => false, + }); + assert!( + match f64::INFINITY.to_string().to_lowercase().as_str() { + "+infinity" | "infinity" => true, + "+inf" | "inf" => true, + _ => false, + }, + "Infinity must write to a string as some casing of inf or infinity, with an optional +." + ); +} + +#[test] +fn neg_infinity_to_str() { + assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() { + "-infinity" | "-inf" => true, + _ => false, + }); + assert!( + match f64::NEG_INFINITY.to_string().to_lowercase().as_str() { + "-infinity" | "-inf" => true, + _ => false, + }, + "Negative Infinity must write to a string as some casing of -inf or -infinity" + ) +} + +#[test] +fn nan_to_str() { + assert!( + match f32::NAN.to_string().to_lowercase().as_str() { + "nan" | "+nan" | "-nan" => true, + _ => false, + }, + "NaNs must write to a string as some casing of nan." + ) +} + +// "+"?("inf"|"infinity") in any case => Infinity +#[test] +fn infinity_from_str() { + assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap()); + assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap()); + assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap()); + assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap()); + // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd + assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap()); +} + +// "-inf"|"-infinity" in any case => Negative Infinity +#[test] +fn neg_infinity_from_str() { + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap()); + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap()); + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap()); + assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap()); +} + +// ("+"|"-"")?"s"?"nan" in any case => qNaN +#[test] +fn qnan_from_str() { + assert!("nan".parse::().unwrap().is_nan()); + assert!("-nan".parse::().unwrap().is_nan()); + assert!("+nan".parse::().unwrap().is_nan()); + assert!("+NAN".parse::().unwrap().is_nan()); + assert!("-NaN".parse::().unwrap().is_nan()); +} diff --git a/library/coretests/tests/num/int_log.rs b/library/coretests/tests/num/int_log.rs new file mode 100644 index 00000000000..60902752dab --- /dev/null +++ b/library/coretests/tests/num/int_log.rs @@ -0,0 +1,188 @@ +//! Tests for the `Integer::{ilog,log2,log10}` methods. + +#[test] +fn checked_ilog() { + assert_eq!(999u32.checked_ilog(10), Some(2)); + assert_eq!(1000u32.checked_ilog(10), Some(3)); + assert_eq!(555u32.checked_ilog(13), Some(2)); + assert_eq!(63u32.checked_ilog(4), Some(2)); + assert_eq!(64u32.checked_ilog(4), Some(3)); + assert_eq!(10460353203u64.checked_ilog(3), Some(21)); + assert_eq!(10460353202u64.checked_ilog(3), Some(20)); + assert_eq!(147808829414345923316083210206383297601u128.checked_ilog(3), Some(80)); + assert_eq!(147808829414345923316083210206383297600u128.checked_ilog(3), Some(79)); + assert_eq!(22528399544939174411840147874772641u128.checked_ilog(19683), Some(8)); + assert_eq!(22528399544939174411840147874772631i128.checked_ilog(19683), Some(7)); + + assert_eq!(0u8.checked_ilog(4), None); + assert_eq!(0u16.checked_ilog(4), None); + assert_eq!(0i8.checked_ilog(4), None); + assert_eq!(0i16.checked_ilog(4), None); + + #[cfg(not(miri))] // Miri is too slow + for i in i16::MIN..=0 { + assert_eq!(i.checked_ilog(4), None, "checking {i}"); + } + #[cfg(not(miri))] // Miri is too slow + for i in 1..=i16::MAX { + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32), "checking {i}"); + } + #[cfg(not(miri))] // Miri is too slow + for i in 1..=u16::MAX { + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32), "checking {i}"); + } +} + +#[test] +fn checked_ilog2() { + assert_eq!(5u32.checked_ilog2(), Some(2)); + assert_eq!(0u64.checked_ilog2(), None); + assert_eq!(128i32.checked_ilog2(), Some(7)); + assert_eq!((-55i16).checked_ilog2(), None); + + assert_eq!(0u8.checked_ilog2(), None); + assert_eq!(0u16.checked_ilog2(), None); + assert_eq!(0i8.checked_ilog2(), None); + assert_eq!(0i16.checked_ilog2(), None); + + assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32)); + assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32)); + assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32)); + + for i in 1..=u8::MAX { + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); + } + #[cfg(not(miri))] // Miri is too slow + for i in 1..=u16::MAX { + // Guard against Android's imprecise f32::ilog2 implementation. + if i != 8192 && i != 32768 { + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); + } + } + for i in i8::MIN..=0 { + assert_eq!(i.checked_ilog2(), None, "checking {i}"); + } + for i in 1..=i8::MAX { + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); + } + #[cfg(not(miri))] // Miri is too slow + for i in i16::MIN..=0 { + assert_eq!(i.checked_ilog2(), None, "checking {i}"); + } + #[cfg(not(miri))] // Miri is too slow + for i in 1..=i16::MAX { + // Guard against Android's imprecise f32::ilog2 implementation. + if i != 8192 { + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); + } + } +} + +#[test] +fn checked_ilog10() { + assert_eq!(0u8.checked_ilog10(), None); + assert_eq!(0u16.checked_ilog10(), None); + assert_eq!(0i8.checked_ilog10(), None); + assert_eq!(0i16.checked_ilog10(), None); + + #[cfg(not(miri))] // Miri is too slow + for i in i16::MIN..=0 { + assert_eq!(i.checked_ilog10(), None, "checking {i}"); + } + #[cfg(not(miri))] // Miri is too slow + for i in 1..=i16::MAX { + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); + } + #[cfg(not(miri))] // Miri is too slow + for i in 1..=u16::MAX { + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); + } + #[cfg(not(miri))] // Miri is too slow + for i in 1..=100_000u32 { + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); + } +} + +macro_rules! ilog10_loop { + ($T:ty, $ilog10_max:expr) => { + assert_eq!(<$T>::MAX.ilog10(), $ilog10_max); + for i in 0..=$ilog10_max { + let p = (10 as $T).pow(i as u32); + if p >= 10 { + assert_eq!((p - 9).ilog10(), i - 1); + assert_eq!((p - 1).ilog10(), i - 1); + } + assert_eq!(p.ilog10(), i); + assert_eq!((p + 1).ilog10(), i); + if p >= 10 { + assert_eq!((p + 9).ilog10(), i); + } + + // also check `x.ilog(10)` + if p >= 10 { + assert_eq!((p - 9).ilog(10), i - 1); + assert_eq!((p - 1).ilog(10), i - 1); + } + assert_eq!(p.ilog(10), i); + assert_eq!((p + 1).ilog(10), i); + if p >= 10 { + assert_eq!((p + 9).ilog(10), i); + } + } + }; +} + +#[test] +fn ilog10_u8() { + ilog10_loop! { u8, 2 } +} + +#[test] +fn ilog10_u16() { + ilog10_loop! { u16, 4 } +} + +#[test] +fn ilog10_u32() { + ilog10_loop! { u32, 9 } +} + +#[test] +fn ilog10_u64() { + ilog10_loop! { u64, 19 } +} + +#[test] +fn ilog10_u128() { + ilog10_loop! { u128, 38 } +} + +#[test] +#[should_panic(expected = "argument of integer logarithm must be positive")] +fn ilog2_of_0_panic() { + let _ = 0u32.ilog2(); +} + +#[test] +#[should_panic(expected = "argument of integer logarithm must be positive")] +fn ilog10_of_0_panic() { + let _ = 0u32.ilog10(); +} + +#[test] +#[should_panic(expected = "argument of integer logarithm must be positive")] +fn ilog3_of_0_panic() { + let _ = 0u32.ilog(3); +} + +#[test] +#[should_panic(expected = "base of integer logarithm must be at least 2")] +fn ilog0_of_1_panic() { + let _ = 1u32.ilog(0); +} + +#[test] +#[should_panic(expected = "base of integer logarithm must be at least 2")] +fn ilog1_of_1_panic() { + let _ = 1u32.ilog(1); +} diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs new file mode 100644 index 00000000000..f13b836378b --- /dev/null +++ b/library/coretests/tests/num/int_macros.rs @@ -0,0 +1,482 @@ +macro_rules! int_module { + ($T:ident, $U:ident) => { + use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; + use core::$T::*; + + const UMAX: $U = $U::MAX; + + use crate::num; + + #[test] + fn test_overflows() { + assert!(MAX > 0); + assert!(MIN <= 0); + assert_eq!(MIN + MAX + 1, 0); + } + + #[test] + fn test_num() { + num::test_num(10 as $T, 2 as $T); + } + + #[test] + fn test_bitwise_operators() { + assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T)); + assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(0b1010 as $T)); + assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(0b1010 as $T)); + assert_eq!(0b1110 as $T, (0b0111 as $T).shl(1)); + assert_eq!(0b0111 as $T, (0b1110 as $T).shr(1)); + assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not()); + } + + test_runtime_and_compiletime! { + + fn test_rem_euclid() { + assert_eq_const_safe!((-1 as $T).rem_euclid(MIN), MAX); + } + + fn test_abs() { + assert_eq_const_safe!((1 as $T).abs(), 1 as $T); + assert_eq_const_safe!((0 as $T).abs(), 0 as $T); + assert_eq_const_safe!((-1 as $T).abs(), 1 as $T); + } + + fn test_signum() { + assert_eq_const_safe!((1 as $T).signum(), 1 as $T); + assert_eq_const_safe!((0 as $T).signum(), 0 as $T); + assert_eq_const_safe!((-0 as $T).signum(), 0 as $T); + assert_eq_const_safe!((-1 as $T).signum(), -1 as $T); + } + + fn test_is_positive() { + assert!((1 as $T).is_positive()); + assert!(!(0 as $T).is_positive()); + assert!(!(-0 as $T).is_positive()); + assert!(!(-1 as $T).is_positive()); + } + + fn test_is_negative() { + assert!(!(1 as $T).is_negative()); + assert!(!(0 as $T).is_negative()); + assert!(!(-0 as $T).is_negative()); + assert!((-1 as $T).is_negative()); + } + } + + const A: $T = 0b0101100; + const B: $T = 0b0100001; + const C: $T = 0b1111001; + + const _0: $T = 0; + const _1: $T = !0; + + test_runtime_and_compiletime! { + fn test_count_ones() { + assert_eq_const_safe!(A.count_ones(), 3); + assert_eq_const_safe!(B.count_ones(), 2); + assert_eq_const_safe!(C.count_ones(), 5); + } + + fn test_count_zeros() { + assert_eq_const_safe!(A.count_zeros(), $T::BITS - 3); + assert_eq_const_safe!(B.count_zeros(), $T::BITS - 2); + assert_eq_const_safe!(C.count_zeros(), $T::BITS - 5); + } + + fn test_leading_trailing_ones() { + const A: $T = 0b0101_1111; + assert_eq_const_safe!(A.trailing_ones(), 5); + assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); + + assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); + + assert_eq_const_safe!(_1.leading_ones(), $T::BITS); + assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); + + assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); + assert_eq_const_safe!(MAX.leading_ones(), 0); + + assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq_const_safe!(MAX.trailing_ones(), $T::BITS - 1); + + assert_eq_const_safe!(_0.leading_ones(), 0); + assert_eq_const_safe!(_0.trailing_ones(), 0); + + const X: $T = 0b0010_1100; + assert_eq_const_safe!(X.leading_ones(), 0); + assert_eq_const_safe!(X.trailing_ones(), 0); + } + + fn test_rotate() { + assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + + // Rotating these should make no difference + // + // We test using 124 bits because to ensure that overlong bit shifts do + // not cause undefined behavior. See #10183. + assert_eq_const_safe!(_0.rotate_left(124), _0); + assert_eq_const_safe!(_1.rotate_left(124), _1); + assert_eq_const_safe!(_0.rotate_right(124), _0); + assert_eq_const_safe!(_1.rotate_right(124), _1); + + // Rotating by 0 should have no effect + assert_eq_const_safe!(A.rotate_left(0), A); + assert_eq_const_safe!(B.rotate_left(0), B); + assert_eq_const_safe!(C.rotate_left(0), C); + // Rotating by a multiple of word size should also have no effect + assert_eq_const_safe!(A.rotate_left(128), A); + assert_eq_const_safe!(B.rotate_left(128), B); + assert_eq_const_safe!(C.rotate_left(128), C); + } + + fn test_swap_bytes() { + assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); + assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); + assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); + + // Swapping these should make no difference + assert_eq_const_safe!(_0.swap_bytes(), _0); + assert_eq_const_safe!(_1.swap_bytes(), _1); + } + + fn test_le() { + assert_eq_const_safe!($T::from_le(A.to_le()), A); + assert_eq_const_safe!($T::from_le(B.to_le()), B); + assert_eq_const_safe!($T::from_le(C.to_le()), C); + assert_eq_const_safe!($T::from_le(_0), _0); + assert_eq_const_safe!($T::from_le(_1), _1); + assert_eq_const_safe!(_0.to_le(), _0); + assert_eq_const_safe!(_1.to_le(), _1); + } + + fn test_be() { + assert_eq_const_safe!($T::from_be(A.to_be()), A); + assert_eq_const_safe!($T::from_be(B.to_be()), B); + assert_eq_const_safe!($T::from_be(C.to_be()), C); + assert_eq_const_safe!($T::from_be(_0), _0); + assert_eq_const_safe!($T::from_be(_1), _1); + assert_eq_const_safe!(_0.to_be(), _0); + assert_eq_const_safe!(_1.to_be(), _1); + } + + fn test_signed_checked_div() { + assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); + assert_eq_const_safe!((5 as $T).checked_div(0), None); + assert_eq_const_safe!(isize::MIN.checked_div(-1), None); + } + + fn test_saturating_abs() { + assert_eq_const_safe!((0 as $T).saturating_abs(), 0); + assert_eq_const_safe!((123 as $T).saturating_abs(), 123); + assert_eq_const_safe!((-123 as $T).saturating_abs(), 123); + assert_eq_const_safe!((MAX - 2).saturating_abs(), MAX - 2); + assert_eq_const_safe!((MAX - 1).saturating_abs(), MAX - 1); + assert_eq_const_safe!(MAX.saturating_abs(), MAX); + assert_eq_const_safe!((MIN + 2).saturating_abs(), MAX - 1); + assert_eq_const_safe!((MIN + 1).saturating_abs(), MAX); + assert_eq_const_safe!(MIN.saturating_abs(), MAX); + } + + fn test_saturating_neg() { + assert_eq_const_safe!((0 as $T).saturating_neg(), 0); + assert_eq_const_safe!((123 as $T).saturating_neg(), -123); + assert_eq_const_safe!((-123 as $T).saturating_neg(), 123); + assert_eq_const_safe!((MAX - 2).saturating_neg(), MIN + 3); + assert_eq_const_safe!((MAX - 1).saturating_neg(), MIN + 2); + assert_eq_const_safe!(MAX.saturating_neg(), MIN + 1); + assert_eq_const_safe!((MIN + 2).saturating_neg(), MAX - 1); + assert_eq_const_safe!((MIN + 1).saturating_neg(), MAX); + assert_eq_const_safe!(MIN.saturating_neg(), MAX); + } + } + + #[test] + fn test_from_str() { + fn from_str(t: &str) -> Option { + std::str::FromStr::from_str(t).ok() + } + assert_eq!(from_str::<$T>("0"), Some(0 as $T)); + assert_eq!(from_str::<$T>("3"), Some(3 as $T)); + assert_eq!(from_str::<$T>("10"), Some(10 as $T)); + assert_eq!(from_str::("123456789"), Some(123456789 as i32)); + assert_eq!(from_str::<$T>("00100"), Some(100 as $T)); + + assert_eq!(from_str::<$T>("-1"), Some(-1 as $T)); + assert_eq!(from_str::<$T>("-3"), Some(-3 as $T)); + assert_eq!(from_str::<$T>("-10"), Some(-10 as $T)); + assert_eq!(from_str::("-123456789"), Some(-123456789 as i32)); + assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T)); + + assert_eq!(from_str::<$T>(""), None); + assert_eq!(from_str::<$T>(" "), None); + assert_eq!(from_str::<$T>("x"), None); + } + + test_runtime_and_compiletime! { + fn test_from_str_radix() { + assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq_const_safe!(i32::from_str_radix("123", 16), Ok(291 as i32)); + assert_eq_const_safe!(i32::from_str_radix("ffff", 16), Ok(65535 as i32)); + assert_eq_const_safe!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32)); + assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); + assert_eq_const_safe!($T::from_str_radix("Z", 36), Ok(35 as $T)); + + assert_eq_const_safe!($T::from_str_radix("-123", 10), Ok(-123 as $T)); + assert_eq_const_safe!($T::from_str_radix("-1001", 2), Ok(-9 as $T)); + assert_eq_const_safe!($T::from_str_radix("-123", 8), Ok(-83 as $T)); + assert_eq_const_safe!(i32::from_str_radix("-123", 16), Ok(-291 as i32)); + assert_eq_const_safe!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32)); + assert_eq_const_safe!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); + assert_eq_const_safe!($T::from_str_radix("-z", 36), Ok(-35 as $T)); + assert_eq_const_safe!($T::from_str_radix("-Z", 36), Ok(-35 as $T)); + + assert!($T::from_str_radix("Z", 35).is_err()); + assert!($T::from_str_radix("-9", 2).is_err()); + assert!($T::from_str_radix("10_0", 10).is_err()); + assert!(u32::from_str_radix("-9", 10).is_err()); + } + + fn test_pow() { + { + const R: $T = 2; + assert_eq_const_safe!(R.pow(2), 4 as $T); + assert_eq_const_safe!(R.pow(0), 1 as $T); + assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + } + + { + const R: $T = MAX; + // use `^` to represent .pow() with no overflow. + // if itest::MAX == 2^j-1, then itest is a `j` bit int, + // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, + // thussaturating_pow the overflowing result is exactly 1. + assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), None); + assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); + assert_eq_const_safe!(R.saturating_pow(2), MAX); + } + + { + // test for negative exponent. + const R: $T = -2; + assert_eq_const_safe!(R.pow(2), 4 as $T); + assert_eq_const_safe!(R.pow(3), -8 as $T); + assert_eq_const_safe!(R.pow(0), 1 as $T); + assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!(R.wrapping_pow(3), -8 as $T); + assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(R.checked_pow(3), Some(-8 as $T)); + assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(3), (-8 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!(R.saturating_pow(3), -8 as $T); + assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + } + } + + fn test_div_floor() { + const A: $T = 8; + const B: $T = 3; + assert_eq_const_safe!(A.div_floor(B), 2); + assert_eq_const_safe!(A.div_floor(-B), -3); + assert_eq_const_safe!((-A).div_floor(B), -3); + assert_eq_const_safe!((-A).div_floor(-B), 2); + } + + fn test_div_ceil() { + const A: $T = 8; + const B: $T = 3; + assert_eq_const_safe!(A.div_ceil(B), 3); + assert_eq_const_safe!(A.div_ceil(-B), -2); + assert_eq_const_safe!((-A).div_ceil(B), -2); + assert_eq_const_safe!((-A).div_ceil(-B), 3); + } + + fn test_next_multiple_of() { + assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); + assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); + assert_eq_const_safe!((16 as $T).next_multiple_of(-8), 16); + assert_eq_const_safe!((23 as $T).next_multiple_of(-8), 16); + assert_eq_const_safe!((-16 as $T).next_multiple_of(8), -16); + assert_eq_const_safe!((-23 as $T).next_multiple_of(8), -16); + assert_eq_const_safe!((-16 as $T).next_multiple_of(-8), -16); + assert_eq_const_safe!((-23 as $T).next_multiple_of(-8), -24); + assert_eq_const_safe!(MIN.next_multiple_of(-1), MIN); + } + + fn test_checked_next_multiple_of() { + assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq_const_safe!((16 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq_const_safe!((23 as $T).checked_next_multiple_of(-8), Some(16)); + assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(8), Some(-16)); + assert_eq_const_safe!((-16 as $T).checked_next_multiple_of(-8), Some(-16)); + assert_eq_const_safe!((-23 as $T).checked_next_multiple_of(-8), Some(-24)); + assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); + assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); + assert_eq_const_safe!(MIN.checked_next_multiple_of(-3), None); + assert_eq_const_safe!(MIN.checked_next_multiple_of(-1), Some(MIN)); + } + + fn test_carrying_add() { + assert_eq_const_safe!(MAX.carrying_add(1, false), (MIN, true)); + assert_eq_const_safe!(MAX.carrying_add(0, true), (MIN, true)); + assert_eq_const_safe!(MAX.carrying_add(1, true), (MIN + 1, true)); + assert_eq_const_safe!(MAX.carrying_add(-1, false), (MAX - 1, false)); + assert_eq_const_safe!(MAX.carrying_add(-1, true), (MAX, false)); // no intermediate overflow + assert_eq_const_safe!(MIN.carrying_add(-1, false), (MAX, true)); + assert_eq_const_safe!(MIN.carrying_add(-1, true), (MIN, false)); // no intermediate overflow + assert_eq_const_safe!((0 as $T).carrying_add(MAX, true), (MIN, true)); + assert_eq_const_safe!((0 as $T).carrying_add(MIN, true), (MIN + 1, false)); + } + + fn test_borrowing_sub() { + assert_eq_const_safe!(MIN.borrowing_sub(1, false), (MAX, true)); + assert_eq_const_safe!(MIN.borrowing_sub(0, true), (MAX, true)); + assert_eq_const_safe!(MIN.borrowing_sub(1, true), (MAX - 1, true)); + assert_eq_const_safe!(MIN.borrowing_sub(-1, false), (MIN + 1, false)); + assert_eq_const_safe!(MIN.borrowing_sub(-1, true), (MIN, false)); // no intermediate overflow + assert_eq_const_safe!(MAX.borrowing_sub(-1, false), (MIN, true)); + assert_eq_const_safe!(MAX.borrowing_sub(-1, true), (MAX, false)); // no intermediate overflow + assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, false), (MIN, true)); + assert_eq_const_safe!((0 as $T).borrowing_sub(MIN, true), (MAX, false)); + } + + fn test_widening_mul() { + assert_eq_const_safe!(MAX.widening_mul(MAX), (1, MAX / 2)); + assert_eq_const_safe!(MIN.widening_mul(MAX), (MIN as $U, MIN / 2)); + assert_eq_const_safe!(MIN.widening_mul(MIN), (0, MAX / 2 + 1)); + } + + fn test_carrying_mul() { + assert_eq_const_safe!(MAX.carrying_mul(MAX, 0), (1, MAX / 2)); + assert_eq_const_safe!( + MAX.carrying_mul(MAX, MAX), + (UMAX / 2 + 1, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul(MAX, MIN), + (UMAX / 2 + 2, MAX / 2 - 1) + ); + assert_eq_const_safe!(MIN.carrying_mul(MAX, 0), (MIN as $U, MIN / 2)); + assert_eq_const_safe!(MIN.carrying_mul(MAX, MAX), (UMAX, MIN / 2)); + assert_eq_const_safe!(MIN.carrying_mul(MAX, MIN), (0, MIN / 2)); + assert_eq_const_safe!(MIN.carrying_mul(MIN, 0), (0, MAX / 2 + 1)); + assert_eq_const_safe!( + MIN.carrying_mul(MIN, MAX), + (UMAX / 2, MAX / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul(MIN, MIN), + (UMAX / 2 + 1, MAX / 2) + ); + } + + fn test_carrying_mul_add() { + assert_eq_const_safe!(MAX.carrying_mul_add(MAX, 0, 0), (1, MAX / 2)); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MAX, 0), + (UMAX / 2 + 1, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MIN, 0), + (UMAX / 2 + 2, MAX / 2 - 1) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MAX, MAX), + (UMAX, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MAX, MIN), + (0, MAX / 2) + ); + assert_eq_const_safe!( + MAX.carrying_mul_add(MAX, MIN, MIN), + (1, MAX / 2 - 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, 0, 0), + (MIN as $U, MIN / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MAX, 0), + (UMAX, MIN / 2) + ); + assert_eq_const_safe!(MIN.carrying_mul_add(MAX, MIN, 0), (0, MIN / 2)); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MAX, MAX), + (UMAX / 2 - 1, MIN / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MAX, MIN), + (UMAX / 2, MIN / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MAX, MIN, MIN), + (UMAX / 2 + 1, MIN / 2 - 1) + ); + assert_eq_const_safe!(MIN.carrying_mul_add(MIN, 0, 0), (0, MAX / 2 + 1)); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MAX, 0), + (UMAX / 2, MAX / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MIN, 0), + (UMAX / 2 + 1, MAX / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MAX, MAX), + (UMAX - 1, MAX / 2 + 1) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MAX, MIN), + (UMAX, MAX / 2) + ); + assert_eq_const_safe!( + MIN.carrying_mul_add(MIN, MIN, MIN), + (0, MAX / 2) + ); + } + + fn test_midpoint() { + assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); + + assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); + assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); + + assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); + assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); + assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); + + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), 0); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), 0); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); + } + } + }; +} diff --git a/library/coretests/tests/num/int_sqrt.rs b/library/coretests/tests/num/int_sqrt.rs new file mode 100644 index 00000000000..d68db0787d2 --- /dev/null +++ b/library/coretests/tests/num/int_sqrt.rs @@ -0,0 +1,248 @@ +macro_rules! tests { + ($isqrt_consistency_check_fn_macro:ident : $($T:ident)+) => { + $( + mod $T { + $isqrt_consistency_check_fn_macro!($T); + + // Check that the following produce the correct values from + // `isqrt`: + // + // * the first and last 128 nonnegative values + // * powers of two, minus one + // * powers of two + // + // For signed types, check that `checked_isqrt` and `isqrt` + // either produce the same numeric value or respectively + // produce `None` and a panic. Make sure to do a consistency + // check for `<$T>::MIN` as well, as no nonnegative values + // negate to it. + // + // For unsigned types check that `isqrt` produces the same + // numeric value for `$T` and `NonZero<$T>`. + #[test] + fn isqrt() { + isqrt_consistency_check(<$T>::MIN); + + for n in (0..=127) + .chain(<$T>::MAX - 127..=<$T>::MAX) + .chain((0..<$T>::MAX.count_ones()).map(|exponent| (1 << exponent) - 1)) + .chain((0..<$T>::MAX.count_ones()).map(|exponent| 1 << exponent)) + { + isqrt_consistency_check(n); + + let isqrt_n = n.isqrt(); + assert!( + isqrt_n + .checked_mul(isqrt_n) + .map(|isqrt_n_squared| isqrt_n_squared <= n) + .unwrap_or(false), + "`{n}.isqrt()` should be lower than {isqrt_n}." + ); + assert!( + (isqrt_n + 1) + .checked_mul(isqrt_n + 1) + .map(|isqrt_n_plus_1_squared| n < isqrt_n_plus_1_squared) + .unwrap_or(true), + "`{n}.isqrt()` should be higher than {isqrt_n})." + ); + } + } + + // Check the square roots of: + // + // * the first 1,024 perfect squares + // * halfway between each of the first 1,024 perfect squares + // and the next perfect square + // * the next perfect square after the each of the first 1,024 + // perfect squares, minus one + // * the last 1,024 perfect squares + // * the last 1,024 perfect squares, minus one + // * halfway between each of the last 1,024 perfect squares + // and the previous perfect square + #[test] + // Skip this test on Miri, as it takes too long to run. + #[cfg(not(miri))] + fn isqrt_extended() { + // The correct value is worked out by using the fact that + // the nth nonzero perfect square is the sum of the first n + // odd numbers: + // + // 1 = 1 + // 4 = 1 + 3 + // 9 = 1 + 3 + 5 + // 16 = 1 + 3 + 5 + 7 + // + // Note also that the last odd number added in is two times + // the square root of the previous perfect square, plus + // one: + // + // 1 = 2*0 + 1 + // 3 = 2*1 + 1 + // 5 = 2*2 + 1 + // 7 = 2*3 + 1 + // + // That means we can add the square root of this perfect + // square once to get about halfway to the next perfect + // square, then we can add the square root of this perfect + // square again to get to the next perfect square, minus + // one, then we can add one to get to the next perfect + // square. + // + // This allows us to, for each of the first 1,024 perfect + // squares, test that the square roots of the following are + // all correct and equal to each other: + // + // * the current perfect square + // * about halfway to the next perfect square + // * the next perfect square, minus one + let mut n: $T = 0; + for sqrt_n in 0..1_024.min((1_u128 << (<$T>::MAX.count_ones()/2)) - 1) as $T { + isqrt_consistency_check(n); + assert_eq!( + n.isqrt(), + sqrt_n, + "`{sqrt_n}.pow(2).isqrt()` should be {sqrt_n}." + ); + + n += sqrt_n; + isqrt_consistency_check(n); + assert_eq!( + n.isqrt(), + sqrt_n, + "{n} is about halfway between `{sqrt_n}.pow(2)` and `{}.pow(2)`, so `{n}.isqrt()` should be {sqrt_n}.", + sqrt_n + 1 + ); + + n += sqrt_n; + isqrt_consistency_check(n); + assert_eq!( + n.isqrt(), + sqrt_n, + "`({}.pow(2) - 1).isqrt()` should be {sqrt_n}.", + sqrt_n + 1 + ); + + n += 1; + } + + // Similarly, for each of the last 1,024 perfect squares, + // check: + // + // * the current perfect square + // * the current perfect square, minus one + // * about halfway to the previous perfect square + // + // `MAX`'s `isqrt` return value is verified in the `isqrt` + // test function above. + let maximum_sqrt = <$T>::MAX.isqrt(); + let mut n = maximum_sqrt * maximum_sqrt; + + for sqrt_n in (maximum_sqrt - 1_024.min((1_u128 << (<$T>::MAX.count_ones()/2)) - 1) as $T..maximum_sqrt).rev() { + isqrt_consistency_check(n); + assert_eq!( + n.isqrt(), + sqrt_n + 1, + "`{0}.pow(2).isqrt()` should be {0}.", + sqrt_n + 1 + ); + + n -= 1; + isqrt_consistency_check(n); + assert_eq!( + n.isqrt(), + sqrt_n, + "`({}.pow(2) - 1).isqrt()` should be {sqrt_n}.", + sqrt_n + 1 + ); + + n -= sqrt_n; + isqrt_consistency_check(n); + assert_eq!( + n.isqrt(), + sqrt_n, + "{n} is about halfway between `{sqrt_n}.pow(2)` and `{}.pow(2)`, so `{n}.isqrt()` should be {sqrt_n}.", + sqrt_n + 1 + ); + + n -= sqrt_n; + } + } + } + )* + }; +} + +macro_rules! signed_check { + ($T:ident) => { + /// This takes an input and, if it's nonnegative or + #[doc = concat!("`", stringify!($T), "::MIN`,")] + /// checks that `isqrt` and `checked_isqrt` produce equivalent results + /// for that input and for the negative of that input. + /// + /// # Note + /// + /// This cannot check that negative inputs to `isqrt` cause panics if + /// panics abort instead of unwind. + fn isqrt_consistency_check(n: $T) { + // `<$T>::MIN` will be negative, so ignore it in this nonnegative + // section. + if n >= 0 { + assert_eq!( + Some(n.isqrt()), + n.checked_isqrt(), + "`{n}.checked_isqrt()` should match `Some({n}.isqrt())`.", + ); + } + + // `wrapping_neg` so that `<$T>::MIN` will negate to itself rather + // than panicking. + let negative_n = n.wrapping_neg(); + + // Zero negated will still be nonnegative, so ignore it in this + // negative section. + if negative_n < 0 { + assert_eq!( + negative_n.checked_isqrt(), + None, + "`({negative_n}).checked_isqrt()` should be `None`, as {negative_n} is negative.", + ); + + // `catch_unwind` only works when panics unwind rather than abort. + #[cfg(panic = "unwind")] + { + std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| (-n).isqrt())).expect_err( + &format!("`({negative_n}).isqrt()` should have panicked, as {negative_n} is negative.") + ); + } + } + } + }; +} + +macro_rules! unsigned_check { + ($T:ident) => { + /// This takes an input and, if it's nonzero, checks that `isqrt` + /// produces the same numeric value for both + #[doc = concat!("`", stringify!($T), "` and ")] + #[doc = concat!("`NonZero<", stringify!($T), ">`.")] + fn isqrt_consistency_check(n: $T) { + // Zero cannot be turned into a `NonZero` value, so ignore it in + // this nonzero section. + if n > 0 { + assert_eq!( + n.isqrt(), + core::num::NonZero::<$T>::new(n) + .expect( + "Was not able to create a new `NonZero` value from a nonzero number." + ) + .isqrt() + .get(), + "`{n}.isqrt` should match `NonZero`'s `{n}.isqrt().get()`.", + ); + } + } + }; +} + +tests!(signed_check: i8 i16 i32 i64 i128); +tests!(unsigned_check: u8 u16 u32 u64 u128); diff --git a/library/coretests/tests/num/midpoint.rs b/library/coretests/tests/num/midpoint.rs new file mode 100644 index 00000000000..71e98006784 --- /dev/null +++ b/library/coretests/tests/num/midpoint.rs @@ -0,0 +1,54 @@ +//! Test the following expectations: +//! - midpoint(a, b) == (a + b) / 2 +//! - midpoint(a, b) == midpoint(b, a) +//! - midpoint(-a, -b) == -midpoint(a, b) + +#[test] +#[cfg(not(miri))] +fn midpoint_obvious_impl_i8() { + for a in i8::MIN..=i8::MAX { + for b in i8::MIN..=i8::MAX { + assert_eq!(i8::midpoint(a, b), ((a as i16 + b as i16) / 2) as i8); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_obvious_impl_u8() { + for a in u8::MIN..=u8::MAX { + for b in u8::MIN..=u8::MAX { + assert_eq!(u8::midpoint(a, b), ((a as u16 + b as u16) / 2) as u8); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_order_expectation_i8() { + for a in i8::MIN..=i8::MAX { + for b in i8::MIN..=i8::MAX { + assert_eq!(i8::midpoint(a, b), i8::midpoint(b, a)); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_order_expectation_u8() { + for a in u8::MIN..=u8::MAX { + for b in u8::MIN..=u8::MAX { + assert_eq!(u8::midpoint(a, b), u8::midpoint(b, a)); + } + } +} + +#[test] +#[cfg(not(miri))] +fn midpoint_negative_expectation() { + for a in 0..=i8::MAX { + for b in 0..=i8::MAX { + assert_eq!(i8::midpoint(-a, -b), -i8::midpoint(a, b)); + } + } +} diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs new file mode 100644 index 00000000000..0add9a01e68 --- /dev/null +++ b/library/coretests/tests/num/mod.rs @@ -0,0 +1,952 @@ +use core::fmt::Debug; +use core::num::{IntErrorKind, ParseIntError, TryFromIntError, can_not_overflow}; +use core::ops::{Add, Div, Mul, Rem, Sub}; +use core::str::FromStr; + +#[macro_use] +mod int_macros; + +mod i128; +mod i16; +mod i32; +mod i64; +mod i8; + +#[macro_use] +mod uint_macros; + +mod u128; +mod u16; +mod u32; +mod u64; +mod u8; + +mod bignum; + +mod const_from; +mod dec2flt; +mod flt2dec; +mod int_log; +mod int_sqrt; +mod midpoint; +mod ops; +mod wrapping; + +mod float_iter_sum_identity; +mod ieee754; +mod nan; + +/// Adds the attribute to all items in the block. +macro_rules! cfg_block { + ($(#[$attr:meta]{$($it:item)*})*) => {$($( + #[$attr] + $it + )*)*} +} + +/// Groups items that assume the pointer width is either 16/32/64, and has to be altered if +/// support for larger/smaller pointer widths are added in the future. +macro_rules! assume_usize_width { + {$($it:item)*} => {#[cfg(not(any( + target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")))] + compile_error!("The current tests of try_from on usize/isize assume that \ + the pointer width is either 16, 32, or 64"); + $($it)* + } +} + +/// Helper function for testing numeric operations +pub fn test_num(ten: T, two: T) +where + T: PartialEq + + Add + + Sub + + Mul + + Div + + Rem + + Debug + + Copy, +{ + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); + assert_eq!(ten.rem(two), ten % two); +} + +/// Helper function for asserting number parsing returns a specific error +fn test_parse(num_str: &str, expected: Result) +where + T: FromStr, + Result: PartialEq + Debug, +{ + assert_eq!(num_str.parse::().map_err(|e| e.kind().clone()), expected) +} + +#[test] +fn from_str_issue7588() { + let u: Option = u8::from_str_radix("1000", 10).ok(); + assert_eq!(u, None); + let s: Option = i16::from_str_radix("80000", 10).ok(); + assert_eq!(s, None); +} + +#[test] +fn test_int_from_str_overflow() { + test_parse::("127", Ok(127)); + test_parse::("128", Err(IntErrorKind::PosOverflow)); + + test_parse::("-128", Ok(-128)); + test_parse::("-129", Err(IntErrorKind::NegOverflow)); + + test_parse::("32767", Ok(32_767)); + test_parse::("32768", Err(IntErrorKind::PosOverflow)); + + test_parse::("-32768", Ok(-32_768)); + test_parse::("-32769", Err(IntErrorKind::NegOverflow)); + + test_parse::("2147483647", Ok(2_147_483_647)); + test_parse::("2147483648", Err(IntErrorKind::PosOverflow)); + + test_parse::("-2147483648", Ok(-2_147_483_648)); + test_parse::("-2147483649", Err(IntErrorKind::NegOverflow)); + + test_parse::("9223372036854775807", Ok(9_223_372_036_854_775_807)); + test_parse::("9223372036854775808", Err(IntErrorKind::PosOverflow)); + + test_parse::("-9223372036854775808", Ok(-9_223_372_036_854_775_808)); + test_parse::("-9223372036854775809", Err(IntErrorKind::NegOverflow)); +} + +#[test] +fn test_can_not_overflow() { + fn can_overflow(radix: u32, input: &str) -> bool + where + T: std::convert::TryFrom, + { + !can_not_overflow::(radix, T::try_from(-1_i8).is_ok(), input.as_bytes()) + } + + // Positive tests: + assert!(!can_overflow::(16, "F")); + assert!(!can_overflow::(16, "FF")); + + assert!(!can_overflow::(10, "9")); + assert!(!can_overflow::(10, "99")); + + // Negative tests: + + // Not currently in std lib (issue: #27728) + fn format_radix(mut x: T, radix: T) -> String + where + T: std::ops::Rem, + T: std::ops::Div, + T: std::cmp::PartialEq, + T: std::default::Default, + T: Copy, + T: Default, + u32: TryFrom, + { + let mut result = vec![]; + + loop { + let m = x % radix; + x = x / radix; + result.push( + std::char::from_digit(m.try_into().ok().unwrap(), radix.try_into().ok().unwrap()) + .unwrap(), + ); + if x == T::default() { + break; + } + } + result.into_iter().rev().collect() + } + + macro_rules! check { + ($($t:ty)*) => ($( + for base in 2..=36 { + let num = (<$t>::MAX as u128) + 1; + + // Calculate the string length for the smallest overflowing number: + let max_len_string = format_radix(num, base as u128); + // Ensure that string length is deemed to potentially overflow: + assert!(can_overflow::<$t>(base, &max_len_string)); + } + )*) + } + + check! { i8 i16 i32 i64 i128 isize usize u8 u16 u32 u64 } + + // Check u128 separately: + for base in 2..=36 { + let num = ::MAX; + let max_len_string = format_radix(num, base as u128); + // base 16 fits perfectly for u128 and won't overflow: + assert_eq!(can_overflow::(base, &max_len_string), base != 16); + } +} + +#[test] +fn test_leading_plus() { + test_parse::("+127", Ok(127)); + test_parse::("+9223372036854775807", Ok(9223372036854775807)); +} + +#[test] +fn test_invalid() { + test_parse::("--129", Err(IntErrorKind::InvalidDigit)); + test_parse::("++129", Err(IntErrorKind::InvalidDigit)); + test_parse::("Съешь", Err(IntErrorKind::InvalidDigit)); + test_parse::("123Hello", Err(IntErrorKind::InvalidDigit)); + test_parse::("--", Err(IntErrorKind::InvalidDigit)); + test_parse::("-", Err(IntErrorKind::InvalidDigit)); + test_parse::("+", Err(IntErrorKind::InvalidDigit)); + test_parse::("-1", Err(IntErrorKind::InvalidDigit)); +} + +#[test] +fn test_empty() { + test_parse::("", Err(IntErrorKind::Empty)); +} + +#[test] +fn test_infallible_try_from_int_error() { + let func = |x: i8| -> Result { Ok(x.try_into()?) }; + + assert!(func(0).is_ok()); +} + +const _TEST_CONST_PARSE: () = { + let Ok(-0x8000) = i16::from_str_radix("-8000", 16) else { panic!() }; + let Ok(12345) = u64::from_str_radix("12345", 10) else { panic!() }; + if let Err(e) = i8::from_str_radix("+", 10) { + let IntErrorKind::InvalidDigit = e.kind() else { panic!() }; + } else { + panic!() + } +}; + +macro_rules! test_impl_from { + ($fn_name:ident, bool, $target: ty) => { + #[test] + fn $fn_name() { + let one: $target = 1; + let zero: $target = 0; + assert_eq!(one, <$target>::from(true)); + assert_eq!(zero, <$target>::from(false)); + } + }; + ($fn_name: ident, $Small: ty, $Large: ty) => { + #[test] + fn $fn_name() { + let small_max = <$Small>::MAX; + let small_min = <$Small>::MIN; + let large_max: $Large = small_max.into(); + let large_min: $Large = small_min.into(); + assert_eq!(large_max as $Small, small_max); + assert_eq!(large_min as $Small, small_min); + } + }; +} + +// Unsigned -> Unsigned +test_impl_from! { test_u8u16, u8, u16 } +test_impl_from! { test_u8u32, u8, u32 } +test_impl_from! { test_u8u64, u8, u64 } +test_impl_from! { test_u8usize, u8, usize } +test_impl_from! { test_u16u32, u16, u32 } +test_impl_from! { test_u16u64, u16, u64 } +test_impl_from! { test_u32u64, u32, u64 } + +// Signed -> Signed +test_impl_from! { test_i8i16, i8, i16 } +test_impl_from! { test_i8i32, i8, i32 } +test_impl_from! { test_i8i64, i8, i64 } +test_impl_from! { test_i8isize, i8, isize } +test_impl_from! { test_i16i32, i16, i32 } +test_impl_from! { test_i16i64, i16, i64 } +test_impl_from! { test_i32i64, i32, i64 } + +// Unsigned -> Signed +test_impl_from! { test_u8i16, u8, i16 } +test_impl_from! { test_u8i32, u8, i32 } +test_impl_from! { test_u8i64, u8, i64 } +test_impl_from! { test_u16i32, u16, i32 } +test_impl_from! { test_u16i64, u16, i64 } +test_impl_from! { test_u32i64, u32, i64 } + +// Bool -> Integer +test_impl_from! { test_boolu8, bool, u8 } +test_impl_from! { test_boolu16, bool, u16 } +test_impl_from! { test_boolu32, bool, u32 } +test_impl_from! { test_boolu64, bool, u64 } +test_impl_from! { test_boolu128, bool, u128 } +test_impl_from! { test_booli8, bool, i8 } +test_impl_from! { test_booli16, bool, i16 } +test_impl_from! { test_booli32, bool, i32 } +test_impl_from! { test_booli64, bool, i64 } +test_impl_from! { test_booli128, bool, i128 } + +// Signed -> Float +test_impl_from! { test_i8f32, i8, f32 } +test_impl_from! { test_i8f64, i8, f64 } +test_impl_from! { test_i16f32, i16, f32 } +test_impl_from! { test_i16f64, i16, f64 } +test_impl_from! { test_i32f64, i32, f64 } + +// Unsigned -> Float +test_impl_from! { test_u8f32, u8, f32 } +test_impl_from! { test_u8f64, u8, f64 } +test_impl_from! { test_u16f32, u16, f32 } +test_impl_from! { test_u16f64, u16, f64 } +test_impl_from! { test_u32f64, u32, f64 } + +// Float -> Float +#[test] +fn test_f32f64() { + let max: f64 = f32::MAX.into(); + assert_eq!(max as f32, f32::MAX); + assert!(max.is_normal()); + + let min: f64 = f32::MIN.into(); + assert_eq!(min as f32, f32::MIN); + assert!(min.is_normal()); + + let min_positive: f64 = f32::MIN_POSITIVE.into(); + assert_eq!(min_positive as f32, f32::MIN_POSITIVE); + assert!(min_positive.is_normal()); + + let epsilon: f64 = f32::EPSILON.into(); + assert_eq!(epsilon as f32, f32::EPSILON); + assert!(epsilon.is_normal()); + + let zero: f64 = (0.0f32).into(); + assert_eq!(zero as f32, 0.0f32); + assert!(zero.is_sign_positive()); + + let neg_zero: f64 = (-0.0f32).into(); + assert_eq!(neg_zero as f32, -0.0f32); + assert!(neg_zero.is_sign_negative()); + + let infinity: f64 = f32::INFINITY.into(); + assert_eq!(infinity as f32, f32::INFINITY); + assert!(infinity.is_infinite()); + assert!(infinity.is_sign_positive()); + + let neg_infinity: f64 = f32::NEG_INFINITY.into(); + assert_eq!(neg_infinity as f32, f32::NEG_INFINITY); + assert!(neg_infinity.is_infinite()); + assert!(neg_infinity.is_sign_negative()); + + let nan: f64 = f32::NAN.into(); + assert!(nan.is_nan()); +} + +/// Conversions where the full width of $source can be represented as $target +macro_rules! test_impl_try_from_always_ok { + ($fn_name:ident, $source:ty, $target: ty) => { + #[test] + fn $fn_name() { + let max = <$source>::MAX; + let min = <$source>::MIN; + let zero: $source = 0; + assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target); + assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target); + assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); + } + }; +} + +test_impl_try_from_always_ok! { test_try_u8u8, u8, u8 } +test_impl_try_from_always_ok! { test_try_u8u16, u8, u16 } +test_impl_try_from_always_ok! { test_try_u8u32, u8, u32 } +test_impl_try_from_always_ok! { test_try_u8u64, u8, u64 } +test_impl_try_from_always_ok! { test_try_u8u128, u8, u128 } +test_impl_try_from_always_ok! { test_try_u8i16, u8, i16 } +test_impl_try_from_always_ok! { test_try_u8i32, u8, i32 } +test_impl_try_from_always_ok! { test_try_u8i64, u8, i64 } +test_impl_try_from_always_ok! { test_try_u8i128, u8, i128 } + +test_impl_try_from_always_ok! { test_try_u16u16, u16, u16 } +test_impl_try_from_always_ok! { test_try_u16u32, u16, u32 } +test_impl_try_from_always_ok! { test_try_u16u64, u16, u64 } +test_impl_try_from_always_ok! { test_try_u16u128, u16, u128 } +test_impl_try_from_always_ok! { test_try_u16i32, u16, i32 } +test_impl_try_from_always_ok! { test_try_u16i64, u16, i64 } +test_impl_try_from_always_ok! { test_try_u16i128, u16, i128 } + +test_impl_try_from_always_ok! { test_try_u32u32, u32, u32 } +test_impl_try_from_always_ok! { test_try_u32u64, u32, u64 } +test_impl_try_from_always_ok! { test_try_u32u128, u32, u128 } +test_impl_try_from_always_ok! { test_try_u32i64, u32, i64 } +test_impl_try_from_always_ok! { test_try_u32i128, u32, i128 } + +test_impl_try_from_always_ok! { test_try_u64u64, u64, u64 } +test_impl_try_from_always_ok! { test_try_u64u128, u64, u128 } +test_impl_try_from_always_ok! { test_try_u64i128, u64, i128 } + +test_impl_try_from_always_ok! { test_try_u128u128, u128, u128 } + +test_impl_try_from_always_ok! { test_try_i8i8, i8, i8 } +test_impl_try_from_always_ok! { test_try_i8i16, i8, i16 } +test_impl_try_from_always_ok! { test_try_i8i32, i8, i32 } +test_impl_try_from_always_ok! { test_try_i8i64, i8, i64 } +test_impl_try_from_always_ok! { test_try_i8i128, i8, i128 } + +test_impl_try_from_always_ok! { test_try_i16i16, i16, i16 } +test_impl_try_from_always_ok! { test_try_i16i32, i16, i32 } +test_impl_try_from_always_ok! { test_try_i16i64, i16, i64 } +test_impl_try_from_always_ok! { test_try_i16i128, i16, i128 } + +test_impl_try_from_always_ok! { test_try_i32i32, i32, i32 } +test_impl_try_from_always_ok! { test_try_i32i64, i32, i64 } +test_impl_try_from_always_ok! { test_try_i32i128, i32, i128 } + +test_impl_try_from_always_ok! { test_try_i64i64, i64, i64 } +test_impl_try_from_always_ok! { test_try_i64i128, i64, i128 } + +test_impl_try_from_always_ok! { test_try_i128i128, i128, i128 } + +test_impl_try_from_always_ok! { test_try_usizeusize, usize, usize } +test_impl_try_from_always_ok! { test_try_isizeisize, isize, isize } + +assume_usize_width! { + test_impl_try_from_always_ok! { test_try_u8usize, u8, usize } + test_impl_try_from_always_ok! { test_try_u8isize, u8, isize } + test_impl_try_from_always_ok! { test_try_i8isize, i8, isize } + + test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } + test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } + + test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } + test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } + test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } + + test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } + test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } + test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } + test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } + } + ); +} + +/// Conversions where max of $source can be represented as $target, +macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok { + ($fn_name:ident, $source:ty, $target:ty) => { + #[test] + fn $fn_name() { + let max = <$source>::MAX; + let min = <$source>::MIN; + let zero: $source = 0; + let neg_one: $source = -1; + assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target); + assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); + assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); + assert!(<$target as TryFrom<$source>>::try_from(neg_one).is_err()); + } + }; +} + +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u8, i8, u8 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u16, i8, u16 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u32, i8, u32 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u64, i8, u64 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u128, i8, u128 } + +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u16, i16, u16 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u32, i16, u32 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u64, i16, u64 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u128, i16, u128 } + +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u32, i32, u32 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u64, i32, u64 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u128, i32, u128 } + +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u64, i64, u64 } +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u128, i64, u128 } + +test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i128u128, i128, u128 } + +assume_usize_width! { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8usize, i8, usize } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16usize, i16, usize } + + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } + } + ); +} + +/// Conversions where max of $source can not be represented as $target, +/// but min can. +macro_rules! test_impl_try_from_unsigned_to_signed_upper_err { + ($fn_name:ident, $source:ty, $target:ty) => { + #[test] + fn $fn_name() { + let max = <$source>::MAX; + let min = <$source>::MIN; + let zero: $source = 0; + assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); + assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target); + assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); + } + }; +} + +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u8i8, u8, i8 } + +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i8, u16, i8 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i16, u16, i16 } + +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i8, u32, i8 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i16, u32, i16 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i32, u32, i32 } + +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i8, u64, i8 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i16, u64, i16 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i32, u64, i32 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i64, u64, i64 } + +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i8, u128, i8 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i16, u128, i16 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i32, u128, i32 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } +test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } + +assume_usize_width! { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } + + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } + } + ); +} + +/// Conversions where min/max of $source can not be represented as $target. +macro_rules! test_impl_try_from_same_sign_err { + ($fn_name:ident, $source:ty, $target:ty) => { + #[test] + fn $fn_name() { + let max = <$source>::MAX; + let min = <$source>::MIN; + let zero: $source = 0; + let t_max = <$target>::MAX; + let t_min = <$target>::MIN; + assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); + if min != 0 { + assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); + } + assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); + assert_eq!( + <$target as TryFrom<$source>>::try_from(t_max as $source).unwrap(), + t_max as $target + ); + assert_eq!( + <$target as TryFrom<$source>>::try_from(t_min as $source).unwrap(), + t_min as $target + ); + } + }; +} + +test_impl_try_from_same_sign_err! { test_try_u16u8, u16, u8 } + +test_impl_try_from_same_sign_err! { test_try_u32u8, u32, u8 } +test_impl_try_from_same_sign_err! { test_try_u32u16, u32, u16 } + +test_impl_try_from_same_sign_err! { test_try_u64u8, u64, u8 } +test_impl_try_from_same_sign_err! { test_try_u64u16, u64, u16 } +test_impl_try_from_same_sign_err! { test_try_u64u32, u64, u32 } + +test_impl_try_from_same_sign_err! { test_try_u128u8, u128, u8 } +test_impl_try_from_same_sign_err! { test_try_u128u16, u128, u16 } +test_impl_try_from_same_sign_err! { test_try_u128u32, u128, u32 } +test_impl_try_from_same_sign_err! { test_try_u128u64, u128, u64 } + +test_impl_try_from_same_sign_err! { test_try_i16i8, i16, i8 } +test_impl_try_from_same_sign_err! { test_try_isizei8, isize, i8 } + +test_impl_try_from_same_sign_err! { test_try_i32i8, i32, i8 } +test_impl_try_from_same_sign_err! { test_try_i32i16, i32, i16 } + +test_impl_try_from_same_sign_err! { test_try_i64i8, i64, i8 } +test_impl_try_from_same_sign_err! { test_try_i64i16, i64, i16 } +test_impl_try_from_same_sign_err! { test_try_i64i32, i64, i32 } + +test_impl_try_from_same_sign_err! { test_try_i128i8, i128, i8 } +test_impl_try_from_same_sign_err! { test_try_i128i16, i128, i16 } +test_impl_try_from_same_sign_err! { test_try_i128i32, i128, i32 } +test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } + +assume_usize_width! { + test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } + test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } + test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + + test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } + + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } + } + ); +} + +/// Conversions where neither the min nor the max of $source can be represented by +/// $target, but max/min of the target can be represented by the source. +macro_rules! test_impl_try_from_signed_to_unsigned_err { + ($fn_name:ident, $source:ty, $target:ty) => { + #[test] + fn $fn_name() { + let max = <$source>::MAX; + let min = <$source>::MIN; + let zero: $source = 0; + let t_max = <$target>::MAX; + let t_min = <$target>::MIN; + assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); + assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); + assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); + assert_eq!( + <$target as TryFrom<$source>>::try_from(t_max as $source).unwrap(), + t_max as $target + ); + assert_eq!( + <$target as TryFrom<$source>>::try_from(t_min as $source).unwrap(), + t_min as $target + ); + } + }; +} + +test_impl_try_from_signed_to_unsigned_err! { test_try_i16u8, i16, u8 } + +test_impl_try_from_signed_to_unsigned_err! { test_try_i32u8, i32, u8 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i32u16, i32, u16 } + +test_impl_try_from_signed_to_unsigned_err! { test_try_i64u8, i64, u8 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i64u16, i64, u16 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i64u32, i64, u32 } + +test_impl_try_from_signed_to_unsigned_err! { test_try_i128u8, i128, u8 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i128u16, i128, u16 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i128u32, i128, u32 } +test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } + +assume_usize_width! { + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } + test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } + + cfg_block! { + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + } + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + } + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } + } + } +} + +macro_rules! test_float { + ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => { + mod $modname { + #[test] + fn min() { + assert_eq!((0.0 as $fty).min(0.0), 0.0); + assert!((0.0 as $fty).min(0.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).min(-0.0), -0.0); + assert!((-0.0 as $fty).min(-0.0).is_sign_negative()); + assert_eq!((9.0 as $fty).min(9.0), 9.0); + assert_eq!((-9.0 as $fty).min(0.0), -9.0); + assert_eq!((0.0 as $fty).min(9.0), 0.0); + assert!((0.0 as $fty).min(9.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).min(9.0), -0.0); + assert!((-0.0 as $fty).min(9.0).is_sign_negative()); + assert_eq!((-0.0 as $fty).min(-9.0), -9.0); + assert_eq!(($inf as $fty).min(9.0), 9.0); + assert_eq!((9.0 as $fty).min($inf), 9.0); + assert_eq!(($inf as $fty).min(-9.0), -9.0); + assert_eq!((-9.0 as $fty).min($inf), -9.0); + assert_eq!(($neginf as $fty).min(9.0), $neginf); + assert_eq!((9.0 as $fty).min($neginf), $neginf); + assert_eq!(($neginf as $fty).min(-9.0), $neginf); + assert_eq!((-9.0 as $fty).min($neginf), $neginf); + assert_eq!(($nan as $fty).min(9.0), 9.0); + assert_eq!(($nan as $fty).min(-9.0), -9.0); + assert_eq!((9.0 as $fty).min($nan), 9.0); + assert_eq!((-9.0 as $fty).min($nan), -9.0); + assert!(($nan as $fty).min($nan).is_nan()); + } + #[test] + fn max() { + assert_eq!((0.0 as $fty).max(0.0), 0.0); + assert!((0.0 as $fty).max(0.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).max(-0.0), -0.0); + assert!((-0.0 as $fty).max(-0.0).is_sign_negative()); + assert_eq!((9.0 as $fty).max(9.0), 9.0); + assert_eq!((-9.0 as $fty).max(0.0), 0.0); + assert!((-9.0 as $fty).max(0.0).is_sign_positive()); + assert_eq!((-9.0 as $fty).max(-0.0), -0.0); + assert!((-9.0 as $fty).max(-0.0).is_sign_negative()); + assert_eq!((0.0 as $fty).max(9.0), 9.0); + assert_eq!((0.0 as $fty).max(-9.0), 0.0); + assert!((0.0 as $fty).max(-9.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).max(-9.0), -0.0); + assert!((-0.0 as $fty).max(-9.0).is_sign_negative()); + assert_eq!(($inf as $fty).max(9.0), $inf); + assert_eq!((9.0 as $fty).max($inf), $inf); + assert_eq!(($inf as $fty).max(-9.0), $inf); + assert_eq!((-9.0 as $fty).max($inf), $inf); + assert_eq!(($neginf as $fty).max(9.0), 9.0); + assert_eq!((9.0 as $fty).max($neginf), 9.0); + assert_eq!(($neginf as $fty).max(-9.0), -9.0); + assert_eq!((-9.0 as $fty).max($neginf), -9.0); + assert_eq!(($nan as $fty).max(9.0), 9.0); + assert_eq!(($nan as $fty).max(-9.0), -9.0); + assert_eq!((9.0 as $fty).max($nan), 9.0); + assert_eq!((-9.0 as $fty).max($nan), -9.0); + assert!(($nan as $fty).max($nan).is_nan()); + } + #[test] + fn minimum() { + assert_eq!((0.0 as $fty).minimum(0.0), 0.0); + assert!((0.0 as $fty).minimum(0.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).minimum(0.0), -0.0); + assert!((-0.0 as $fty).minimum(0.0).is_sign_negative()); + assert_eq!((-0.0 as $fty).minimum(-0.0), -0.0); + assert!((-0.0 as $fty).minimum(-0.0).is_sign_negative()); + assert_eq!((9.0 as $fty).minimum(9.0), 9.0); + assert_eq!((-9.0 as $fty).minimum(0.0), -9.0); + assert_eq!((0.0 as $fty).minimum(9.0), 0.0); + assert!((0.0 as $fty).minimum(9.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).minimum(9.0), -0.0); + assert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); + assert_eq!((-0.0 as $fty).minimum(-9.0), -9.0); + assert_eq!(($inf as $fty).minimum(9.0), 9.0); + assert_eq!((9.0 as $fty).minimum($inf), 9.0); + assert_eq!(($inf as $fty).minimum(-9.0), -9.0); + assert_eq!((-9.0 as $fty).minimum($inf), -9.0); + assert_eq!(($neginf as $fty).minimum(9.0), $neginf); + assert_eq!((9.0 as $fty).minimum($neginf), $neginf); + assert_eq!(($neginf as $fty).minimum(-9.0), $neginf); + assert_eq!((-9.0 as $fty).minimum($neginf), $neginf); + assert!(($nan as $fty).minimum(9.0).is_nan()); + assert!(($nan as $fty).minimum(-9.0).is_nan()); + assert!((9.0 as $fty).minimum($nan).is_nan()); + assert!((-9.0 as $fty).minimum($nan).is_nan()); + assert!(($nan as $fty).minimum($nan).is_nan()); + } + #[test] + fn maximum() { + assert_eq!((0.0 as $fty).maximum(0.0), 0.0); + assert!((0.0 as $fty).maximum(0.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).maximum(0.0), 0.0); + assert!((-0.0 as $fty).maximum(0.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).maximum(-0.0), -0.0); + assert!((-0.0 as $fty).maximum(-0.0).is_sign_negative()); + assert_eq!((9.0 as $fty).maximum(9.0), 9.0); + assert_eq!((-9.0 as $fty).maximum(0.0), 0.0); + assert!((-9.0 as $fty).maximum(0.0).is_sign_positive()); + assert_eq!((-9.0 as $fty).maximum(-0.0), -0.0); + assert!((-9.0 as $fty).maximum(-0.0).is_sign_negative()); + assert_eq!((0.0 as $fty).maximum(9.0), 9.0); + assert_eq!((0.0 as $fty).maximum(-9.0), 0.0); + assert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).maximum(-9.0), -0.0); + assert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); + assert_eq!(($inf as $fty).maximum(9.0), $inf); + assert_eq!((9.0 as $fty).maximum($inf), $inf); + assert_eq!(($inf as $fty).maximum(-9.0), $inf); + assert_eq!((-9.0 as $fty).maximum($inf), $inf); + assert_eq!(($neginf as $fty).maximum(9.0), 9.0); + assert_eq!((9.0 as $fty).maximum($neginf), 9.0); + assert_eq!(($neginf as $fty).maximum(-9.0), -9.0); + assert_eq!((-9.0 as $fty).maximum($neginf), -9.0); + assert!(($nan as $fty).maximum(9.0).is_nan()); + assert!(($nan as $fty).maximum(-9.0).is_nan()); + assert!((9.0 as $fty).maximum($nan).is_nan()); + assert!((-9.0 as $fty).maximum($nan).is_nan()); + assert!(($nan as $fty).maximum($nan).is_nan()); + } + #[test] + fn midpoint() { + assert_eq!((0.5 as $fty).midpoint(0.5), 0.5); + assert_eq!((0.5 as $fty).midpoint(2.5), 1.5); + assert_eq!((3.0 as $fty).midpoint(4.0), 3.5); + assert_eq!((-3.0 as $fty).midpoint(4.0), 0.5); + assert_eq!((3.0 as $fty).midpoint(-4.0), -0.5); + assert_eq!((-3.0 as $fty).midpoint(-4.0), -3.5); + assert_eq!((0.0 as $fty).midpoint(0.0), 0.0); + assert_eq!((-0.0 as $fty).midpoint(-0.0), -0.0); + assert_eq!((-5.0 as $fty).midpoint(5.0), 0.0); + assert_eq!(($max as $fty).midpoint($min), 0.0); + assert_eq!(($min as $fty).midpoint($max), -0.0); + assert_eq!(($max as $fty).midpoint($min_pos), $max / 2.); + assert_eq!((-$max as $fty).midpoint($min_pos), -$max / 2.); + assert_eq!(($max as $fty).midpoint(-$min_pos), $max / 2.); + assert_eq!((-$max as $fty).midpoint(-$min_pos), -$max / 2.); + assert_eq!(($min_pos as $fty).midpoint($max), $max / 2.); + assert_eq!(($min_pos as $fty).midpoint(-$max), -$max / 2.); + assert_eq!((-$min_pos as $fty).midpoint($max), $max / 2.); + assert_eq!((-$min_pos as $fty).midpoint(-$max), -$max / 2.); + assert_eq!(($max as $fty).midpoint($max), $max); + assert_eq!(($min_pos as $fty).midpoint($min_pos), $min_pos); + assert_eq!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos); + assert_eq!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5); + assert_eq!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5); + assert_eq!(($inf as $fty).midpoint($inf), $inf); + assert_eq!(($neginf as $fty).midpoint($neginf), $neginf); + assert!(($nan as $fty).midpoint(1.0).is_nan()); + assert!((1.0 as $fty).midpoint($nan).is_nan()); + assert!(($nan as $fty).midpoint($nan).is_nan()); + + // test if large differences in magnitude are still correctly computed. + // NOTE: that because of how small x and y are, x + y can never overflow + // so (x + y) / 2.0 is always correct + // in particular, `2.pow(i)` will never be at the max exponent, so it could + // be safely doubled, while j is significantly smaller. + for i in $max_exp.saturating_sub(64)..$max_exp { + for j in 0..64u8 { + let large = <$fty>::from(2.0f32).powi(i); + // a much smaller number, such that there is no chance of overflow to test + // potential double rounding in midpoint's implementation. + let small = <$fty>::from(2.0f32).powi($max_exp - 1) + * <$fty>::EPSILON + * <$fty>::from(j); + + let naive = (large + small) / 2.0; + let midpoint = large.midpoint(small); + + assert_eq!(naive, midpoint); + } + } + } + #[test] + fn rem_euclid() { + let a: $fty = 42.0; + assert!($inf.rem_euclid(a).is_nan()); + assert_eq!(a.rem_euclid($inf), a); + assert!(a.rem_euclid($nan).is_nan()); + assert!($inf.rem_euclid($inf).is_nan()); + assert!($inf.rem_euclid($nan).is_nan()); + assert!($nan.rem_euclid($inf).is_nan()); + } + #[test] + fn div_euclid() { + let a: $fty = 42.0; + assert_eq!(a.div_euclid($inf), 0.0); + assert!(a.div_euclid($nan).is_nan()); + assert!($inf.div_euclid($inf).is_nan()); + assert!($inf.div_euclid($nan).is_nan()); + assert!($nan.div_euclid($inf).is_nan()); + } + } + }; +} + +test_float!( + f32, + f32, + f32::INFINITY, + f32::NEG_INFINITY, + f32::NAN, + f32::MIN, + f32::MAX, + f32::MIN_POSITIVE, + f32::MAX_EXP +); +test_float!( + f64, + f64, + f64::INFINITY, + f64::NEG_INFINITY, + f64::NAN, + f64::MIN, + f64::MAX, + f64::MIN_POSITIVE, + f64::MAX_EXP +); diff --git a/library/coretests/tests/num/nan.rs b/library/coretests/tests/num/nan.rs new file mode 100644 index 00000000000..ef81988c961 --- /dev/null +++ b/library/coretests/tests/num/nan.rs @@ -0,0 +1,7 @@ +#[test] +fn test_nan() { + let x = "NaN".to_string(); + assert_eq!(format!("{}", f64::NAN), x); + assert_eq!(format!("{:e}", f64::NAN), x); + assert_eq!(format!("{:E}", f64::NAN), x); +} diff --git a/library/coretests/tests/num/ops.rs b/library/coretests/tests/num/ops.rs new file mode 100644 index 00000000000..7b2aad48978 --- /dev/null +++ b/library/coretests/tests/num/ops.rs @@ -0,0 +1,238 @@ +use core::ops::*; + +// For types L and R, checks that a trait implementation exists for +// * binary ops: L op R, L op &R, &L op R and &L op &R +// * assign ops: &mut L op R, &mut L op &R +macro_rules! impl_defined { + ($op:ident, $method:ident($lhs:literal, $rhs:literal), $result:literal, $lt:ty, $rt:ty) => { + let lhs = $lhs as $lt; + let rhs = $rhs as $rt; + assert_eq!($result as $lt, $op::$method(lhs, rhs)); + assert_eq!($result as $lt, $op::$method(lhs, &rhs)); + assert_eq!($result as $lt, $op::$method(&lhs, rhs)); + assert_eq!($result as $lt, $op::$method(&lhs, &rhs)); + }; + ($op:ident, $method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $lt:ty, $rt:ty) => { + let rhs = $rhs as $rt; + let mut lhs = $lhs as $lt; + $op::$method(&mut lhs, rhs); + assert_eq!($result as $lt, lhs); + + let mut lhs = $lhs as $lt; + $op::$method(&mut lhs, &rhs); + assert_eq!($result as $lt, lhs); + }; +} + +// For all specified types T, checks that a trait implementation exists for +// * binary ops: T op T, T op &T, &T op T and &T op &T +// * assign ops: &mut T op T, &mut T op &T +// * unary ops: op T and op &T +macro_rules! impls_defined { + ($op:ident, $method:ident($lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {$( + impl_defined!($op, $method($lhs, $rhs), $result, $t, $t); + )+}; + ($op:ident, $method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {$( + impl_defined!($op, $method(&mut $lhs, $rhs), $result, $t, $t); + )+}; + ($op:ident, $method:ident($operand:literal), $result:literal, $($t:ty),+) => {$( + let operand = $operand as $t; + assert_eq!($result as $t, $op::$method(operand)); + assert_eq!($result as $t, $op::$method(&operand)); + )+}; +} + +macro_rules! test_op { + ($fn_name:ident, $op:ident::$method:ident($lhs:literal), $result:literal, $($t:ty),+) => { + #[test] + fn $fn_name() { + impls_defined!($op, $method($lhs), $result, $($t),+); + } + }; +} + +test_op!(test_neg_defined, Neg::neg(0), 0, i8, i16, i32, i64, i128, f32, f64); + +test_op!(test_not_defined_bool, Not::not(true), false, bool); + +macro_rules! test_arith_op { + ($fn_name:ident, $op:ident::$method:ident($lhs:literal, $rhs:literal)) => { + #[test] + fn $fn_name() { + impls_defined!( + $op, + $method($lhs, $rhs), + 0, + i8, + i16, + i32, + i64, + i128, + isize, + u8, + u16, + u32, + u64, + u128, + usize, + f32, + f64 + ); + } + }; + ($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal)) => { + #[test] + fn $fn_name() { + impls_defined!( + $op, + $method(&mut $lhs, $rhs), + 0, + i8, + i16, + i32, + i64, + i128, + isize, + u8, + u16, + u32, + u64, + u128, + usize, + f32, + f64 + ); + } + }; +} + +test_arith_op!(test_add_defined, Add::add(0, 0)); +test_arith_op!(test_add_assign_defined, AddAssign::add_assign(&mut 0, 0)); +test_arith_op!(test_sub_defined, Sub::sub(0, 0)); +test_arith_op!(test_sub_assign_defined, SubAssign::sub_assign(&mut 0, 0)); +test_arith_op!(test_mul_defined, Mul::mul(0, 0)); +test_arith_op!(test_mul_assign_defined, MulAssign::mul_assign(&mut 0, 0)); +test_arith_op!(test_div_defined, Div::div(0, 1)); +test_arith_op!(test_div_assign_defined, DivAssign::div_assign(&mut 0, 1)); +test_arith_op!(test_rem_defined, Rem::rem(0, 1)); +test_arith_op!(test_rem_assign_defined, RemAssign::rem_assign(&mut 0, 1)); + +macro_rules! test_bitop { + ($test_name:ident, $op:ident::$method:ident) => { + #[test] + fn $test_name() { + impls_defined!( + $op, + $method(0, 0), + 0, + i8, + i16, + i32, + i64, + i128, + isize, + u8, + u16, + u32, + u64, + u128, + usize + ); + impls_defined!($op, $method(false, false), false, bool); + } + }; +} +macro_rules! test_bitop_assign { + ($test_name:ident, $op:ident::$method:ident) => { + #[test] + fn $test_name() { + impls_defined!( + $op, + $method(&mut 0, 0), + 0, + i8, + i16, + i32, + i64, + i128, + isize, + u8, + u16, + u32, + u64, + u128, + usize + ); + impls_defined!($op, $method(&mut false, false), false, bool); + } + }; +} + +test_bitop!(test_bitand_defined, BitAnd::bitand); +test_bitop_assign!(test_bitand_assign_defined, BitAndAssign::bitand_assign); +test_bitop!(test_bitor_defined, BitOr::bitor); +test_bitop_assign!(test_bitor_assign_defined, BitOrAssign::bitor_assign); +test_bitop!(test_bitxor_defined, BitXor::bitxor); +test_bitop_assign!(test_bitxor_assign_defined, BitXorAssign::bitxor_assign); + +macro_rules! test_shift_inner { + ($op:ident::$method:ident, $lt:ty, $($rt:ty),+) => { + $(impl_defined!($op, $method(0,0), 0, $lt, $rt);)+ + }; + ($op:ident::$method:ident, $lt:ty) => { + test_shift_inner!( + $op::$method, $lt, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize + ); + }; +} + +macro_rules! test_shift { + ($op:ident::$method:ident, $($lt:ty),+) => { + $(test_shift_inner!($op::$method, $lt);)+ + }; + ($test_name:ident, $op:ident::$method:ident) => { + #[test] + fn $test_name() { + test_shift!( + $op::$method, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize + ); + } + }; +} + +macro_rules! test_shift_assign_inner { + ($op:ident::$method:ident, $lt:ty, $($rt:ty),+) => { + $(impl_defined!($op, $method(&mut 0,0), 0, $lt, $rt);)+ + }; + ($op:ident::$method:ident, $lt:ty) => { + test_shift_assign_inner!( + $op::$method, $lt, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize + ); + }; +} + +macro_rules! test_shift_assign { + ($op:ident::$method:ident, $($lt:ty),+) => { + $(test_shift_assign_inner!($op::$method, $lt);)+ + }; + ($test_name:ident, $op:ident::$method:ident) => { + #[test] + fn $test_name() { + test_shift_assign!( + $op::$method, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize + ); + } + }; +} +test_shift!(test_shl_defined, Shl::shl); +test_shift_assign!(test_shl_assign_defined, ShlAssign::shl_assign); +test_shift!(test_shr_defined, Shr::shr); +test_shift_assign!(test_shr_assign_defined, ShrAssign::shr_assign); diff --git a/library/coretests/tests/num/u128.rs b/library/coretests/tests/num/u128.rs new file mode 100644 index 00000000000..a7b0f9effef --- /dev/null +++ b/library/coretests/tests/num/u128.rs @@ -0,0 +1 @@ +uint_module!(u128); diff --git a/library/coretests/tests/num/u16.rs b/library/coretests/tests/num/u16.rs new file mode 100644 index 00000000000..010596a34a5 --- /dev/null +++ b/library/coretests/tests/num/u16.rs @@ -0,0 +1 @@ +uint_module!(u16); diff --git a/library/coretests/tests/num/u32.rs b/library/coretests/tests/num/u32.rs new file mode 100644 index 00000000000..687d3bbaa90 --- /dev/null +++ b/library/coretests/tests/num/u32.rs @@ -0,0 +1 @@ +uint_module!(u32); diff --git a/library/coretests/tests/num/u64.rs b/library/coretests/tests/num/u64.rs new file mode 100644 index 00000000000..ee55071e949 --- /dev/null +++ b/library/coretests/tests/num/u64.rs @@ -0,0 +1 @@ +uint_module!(u64); diff --git a/library/coretests/tests/num/u8.rs b/library/coretests/tests/num/u8.rs new file mode 100644 index 00000000000..12b038ce0f7 --- /dev/null +++ b/library/coretests/tests/num/u8.rs @@ -0,0 +1 @@ +uint_module!(u8); diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs new file mode 100644 index 00000000000..99a2d4cd462 --- /dev/null +++ b/library/coretests/tests/num/uint_macros.rs @@ -0,0 +1,321 @@ +macro_rules! uint_module { + ($T:ident) => { + use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; + use core::$T::*; + + use crate::num; + + #[test] + fn test_overflows() { + assert!(MAX > 0); + assert!(MIN <= 0); + assert!((MIN + MAX).wrapping_add(1) == 0); + } + + #[test] + fn test_num() { + num::test_num(10 as $T, 2 as $T); + } + + #[test] + fn test_bitwise_operators() { + assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T)); + assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T)); + assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T)); + assert!(0b1110 as $T == (0b0111 as $T).shl(1)); + assert!(0b0111 as $T == (0b1110 as $T).shr(1)); + assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not()); + } + + const A: $T = 0b0101100; + const B: $T = 0b0100001; + const C: $T = 0b1111001; + + const _0: $T = 0; + const _1: $T = !0; + + test_runtime_and_compiletime! { + fn test_count_ones() { + assert!(A.count_ones() == 3); + assert!(B.count_ones() == 2); + assert!(C.count_ones() == 5); + } + + fn test_count_zeros() { + assert!(A.count_zeros() == $T::BITS - 3); + assert!(B.count_zeros() == $T::BITS - 2); + assert!(C.count_zeros() == $T::BITS - 5); + } + + fn test_leading_trailing_ones() { + const A: $T = 0b0101_1111; + assert_eq_const_safe!(A.trailing_ones(), 5); + assert_eq_const_safe!((!A).leading_ones(), $T::BITS - 7); + + assert_eq_const_safe!(A.reverse_bits().leading_ones(), 5); + + assert_eq_const_safe!(_1.leading_ones(), $T::BITS); + assert_eq_const_safe!(_1.trailing_ones(), $T::BITS); + + assert_eq_const_safe!((_1 << 1).trailing_ones(), 0); + assert_eq_const_safe!((_1 >> 1).leading_ones(), 0); + + assert_eq_const_safe!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq_const_safe!((_1 >> 1).trailing_ones(), $T::BITS - 1); + + assert_eq_const_safe!(_0.leading_ones(), 0); + assert_eq_const_safe!(_0.trailing_ones(), 0); + + const X: $T = 0b0010_1100; + assert_eq_const_safe!(X.leading_ones(), 0); + assert_eq_const_safe!(X.trailing_ones(), 0); + } + + fn test_rotate() { + assert_eq_const_safe!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); + assert_eq_const_safe!(B.rotate_left(3).rotate_left(2).rotate_right(5), B); + assert_eq_const_safe!(C.rotate_left(6).rotate_right(2).rotate_right(4), C); + + // Rotating these should make no difference + // + // We test using 124 bits because to ensure that overlong bit shifts do + // not cause undefined behavior. See #10183. + assert_eq_const_safe!(_0.rotate_left(124), _0); + assert_eq_const_safe!(_1.rotate_left(124), _1); + assert_eq_const_safe!(_0.rotate_right(124), _0); + assert_eq_const_safe!(_1.rotate_right(124), _1); + + // Rotating by 0 should have no effect + assert_eq_const_safe!(A.rotate_left(0), A); + assert_eq_const_safe!(B.rotate_left(0), B); + assert_eq_const_safe!(C.rotate_left(0), C); + // Rotating by a multiple of word size should also have no effect + assert_eq_const_safe!(A.rotate_left(128), A); + assert_eq_const_safe!(B.rotate_left(128), B); + assert_eq_const_safe!(C.rotate_left(128), C); + } + + fn test_swap_bytes() { + assert_eq_const_safe!(A.swap_bytes().swap_bytes(), A); + assert_eq_const_safe!(B.swap_bytes().swap_bytes(), B); + assert_eq_const_safe!(C.swap_bytes().swap_bytes(), C); + + // Swapping these should make no difference + assert_eq_const_safe!(_0.swap_bytes(), _0); + assert_eq_const_safe!(_1.swap_bytes(), _1); + } + + fn test_reverse_bits() { + assert_eq_const_safe!(A.reverse_bits().reverse_bits(), A); + assert_eq_const_safe!(B.reverse_bits().reverse_bits(), B); + assert_eq_const_safe!(C.reverse_bits().reverse_bits(), C); + + // Swapping these should make no difference + assert_eq_const_safe!(_0.reverse_bits(), _0); + assert_eq_const_safe!(_1.reverse_bits(), _1); + } + + fn test_le() { + assert_eq_const_safe!($T::from_le(A.to_le()), A); + assert_eq_const_safe!($T::from_le(B.to_le()), B); + assert_eq_const_safe!($T::from_le(C.to_le()), C); + assert_eq_const_safe!($T::from_le(_0), _0); + assert_eq_const_safe!($T::from_le(_1), _1); + assert_eq_const_safe!(_0.to_le(), _0); + assert_eq_const_safe!(_1.to_le(), _1); + } + + fn test_be() { + assert_eq_const_safe!($T::from_be(A.to_be()), A); + assert_eq_const_safe!($T::from_be(B.to_be()), B); + assert_eq_const_safe!($T::from_be(C.to_be()), C); + assert_eq_const_safe!($T::from_be(_0), _0); + assert_eq_const_safe!($T::from_be(_1), _1); + assert_eq_const_safe!(_0.to_be(), _0); + assert_eq_const_safe!(_1.to_be(), _1); + } + + fn test_unsigned_checked_div() { + assert_eq_const_safe!((10 as $T).checked_div(2), Some(5)); + assert_eq_const_safe!((5 as $T).checked_div(0), None); + } + } + + fn from_str(t: &str) -> Option { + core::str::FromStr::from_str(t).ok() + } + + #[test] + pub fn test_from_str() { + assert_eq!(from_str::<$T>("0"), Some(0 as $T)); + assert_eq!(from_str::<$T>("3"), Some(3 as $T)); + assert_eq!(from_str::<$T>("10"), Some(10 as $T)); + assert_eq!(from_str::("123456789"), Some(123456789 as u32)); + assert_eq!(from_str::<$T>("00100"), Some(100 as $T)); + + assert_eq!(from_str::<$T>(""), None); + assert_eq!(from_str::<$T>(" "), None); + assert_eq!(from_str::<$T>("x"), None); + } + + test_runtime_and_compiletime! { + fn test_parse_bytes() { + assert_eq_const_safe!($T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq_const_safe!($T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq_const_safe!($T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq_const_safe!(u16::from_str_radix("123", 16), Ok(291 as u16)); + assert_eq_const_safe!(u16::from_str_radix("ffff", 16), Ok(65535 as u16)); + assert_eq_const_safe!($T::from_str_radix("z", 36), Ok(35 as $T)); + + assert!($T::from_str_radix("Z", 10).is_err()); + assert!($T::from_str_radix("_", 2).is_err()); + } + + fn test_pow() { + { + const R: $T = 2; + assert_eq_const_safe!(R.pow(2), 4 as $T); + assert_eq_const_safe!(R.pow(0), 1 as $T); + assert_eq_const_safe!(R.wrapping_pow(2), 4 as $T); + assert_eq_const_safe!(R.wrapping_pow(0), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), Some(4 as $T)); + assert_eq_const_safe!(R.checked_pow(0), Some(1 as $T)); + assert_eq_const_safe!(R.overflowing_pow(2), (4 as $T, false)); + assert_eq_const_safe!(R.overflowing_pow(0), (1 as $T, false)); + assert_eq_const_safe!(R.saturating_pow(2), 4 as $T); + assert_eq_const_safe!(R.saturating_pow(0), 1 as $T); + } + + { + const R: $T = $T::MAX; + // use `^` to represent .pow() with no overflow. + // if itest::MAX == 2^j-1, then itest is a `j` bit int, + // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`, + // thussaturating_pow the overflowing result is exactly 1. + assert_eq_const_safe!(R.wrapping_pow(2), 1 as $T); + assert_eq_const_safe!(R.checked_pow(2), None); + assert_eq_const_safe!(R.overflowing_pow(2), (1 as $T, true)); + assert_eq_const_safe!(R.saturating_pow(2), MAX); + } + } + + fn test_isqrt() { + assert_eq_const_safe!((0 as $T).isqrt(), 0 as $T); + assert_eq_const_safe!((1 as $T).isqrt(), 1 as $T); + assert_eq_const_safe!((2 as $T).isqrt(), 1 as $T); + assert_eq_const_safe!((99 as $T).isqrt(), 9 as $T); + assert_eq_const_safe!((100 as $T).isqrt(), 10 as $T); + assert_eq_const_safe!($T::MAX.isqrt(), (1 << ($T::BITS / 2)) - 1); + } + } + + #[cfg(not(miri))] // Miri is too slow + #[test] + fn test_lots_of_isqrt() { + let n_max: $T = (1024 * 1024).min($T::MAX as u128) as $T; + for n in 0..=n_max { + let isqrt: $T = n.isqrt(); + + assert!(isqrt.pow(2) <= n); + assert!(isqrt + 1 == (1 as $T) << ($T::BITS / 2) || (isqrt + 1).pow(2) > n); + } + + for n in ($T::MAX - 255)..=$T::MAX { + let isqrt: $T = n.isqrt(); + + assert!(isqrt.pow(2) <= n); + assert!(isqrt + 1 == (1 as $T) << ($T::BITS / 2) || (isqrt + 1).pow(2) > n); + } + } + + test_runtime_and_compiletime! { + fn test_div_floor() { + assert_eq_const_safe!((8 as $T).div_floor(3), 2); + } + + fn test_div_ceil() { + assert_eq_const_safe!((8 as $T).div_ceil(3), 3); + } + + fn test_next_multiple_of() { + assert_eq_const_safe!((16 as $T).next_multiple_of(8), 16); + assert_eq_const_safe!((23 as $T).next_multiple_of(8), 24); + assert_eq_const_safe!(MAX.next_multiple_of(1), MAX); + } + + fn test_checked_next_multiple_of() { + assert_eq_const_safe!((16 as $T).checked_next_multiple_of(8), Some(16)); + assert_eq_const_safe!((23 as $T).checked_next_multiple_of(8), Some(24)); + assert_eq_const_safe!((1 as $T).checked_next_multiple_of(0), None); + assert_eq_const_safe!(MAX.checked_next_multiple_of(2), None); + } + + fn test_is_next_multiple_of() { + assert!((12 as $T).is_multiple_of(4)); + assert!(!(12 as $T).is_multiple_of(5)); + assert!((0 as $T).is_multiple_of(0)); + assert!(!(12 as $T).is_multiple_of(0)); + } + + fn test_carrying_add() { + assert_eq_const_safe!($T::MAX.carrying_add(1, false), (0, true)); + assert_eq_const_safe!($T::MAX.carrying_add(0, true), (0, true)); + assert_eq_const_safe!($T::MAX.carrying_add(1, true), (1, true)); + + assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); + assert_eq_const_safe!($T::MIN.carrying_add(0, true), (1, false)); + assert_eq_const_safe!($T::MIN.carrying_add($T::MAX, true), (0, true)); + } + + fn test_borrowing_sub() { + assert_eq_const_safe!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq_const_safe!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq_const_safe!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + + assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); + assert_eq_const_safe!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); + assert_eq_const_safe!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); + } + + fn test_widening_mul() { + assert_eq_const_safe!($T::MAX.widening_mul($T::MAX), (1, $T::MAX - 1)); + } + + fn test_carrying_mul() { + assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, 0), (1, $T::MAX - 1)); + assert_eq_const_safe!($T::MAX.carrying_mul($T::MAX, $T::MAX), (0, $T::MAX)); + } + + fn test_carrying_mul_add() { + assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, 0, 0), (1, $T::MAX - 1)); + assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, 0), (0, $T::MAX)); + assert_eq_const_safe!($T::MAX.carrying_mul_add($T::MAX, $T::MAX, $T::MAX), ($T::MAX, $T::MAX)); + } + + fn test_midpoint() { + assert_eq_const_safe!(<$T>::midpoint(1, 3), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 1), 2); + + assert_eq_const_safe!(<$T>::midpoint(0, 0), 0); + assert_eq_const_safe!(<$T>::midpoint(0, 2), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 0), 1); + assert_eq_const_safe!(<$T>::midpoint(2, 2), 2); + + assert_eq_const_safe!(<$T>::midpoint(1, 4), 2); + assert_eq_const_safe!(<$T>::midpoint(4, 1), 2); + assert_eq_const_safe!(<$T>::midpoint(3, 4), 3); + assert_eq_const_safe!(<$T>::midpoint(4, 3), 3); + + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + + assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3); + assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); + } + } + }; +} diff --git a/library/coretests/tests/num/wrapping.rs b/library/coretests/tests/num/wrapping.rs new file mode 100644 index 00000000000..0b9fca8455b --- /dev/null +++ b/library/coretests/tests/num/wrapping.rs @@ -0,0 +1,316 @@ +use core::num::Wrapping; + +macro_rules! wrapping_operation { + ($result:expr, $lhs:ident $op:tt $rhs:expr) => { + assert_eq!($result, $lhs $op $rhs); + assert_eq!($result, &$lhs $op $rhs); + assert_eq!($result, $lhs $op &$rhs); + assert_eq!($result, &$lhs $op &$rhs); + }; + ($result:expr, $op:tt $expr:expr) => { + assert_eq!($result, $op $expr); + assert_eq!($result, $op &$expr); + }; +} + +macro_rules! wrapping_assignment { + ($result:expr, $lhs:ident $op:tt $rhs:expr) => { + let mut lhs1 = $lhs; + lhs1 $op $rhs; + assert_eq!($result, lhs1); + + let mut lhs2 = $lhs; + lhs2 $op &$rhs; + assert_eq!($result, lhs2); + }; +} + +macro_rules! wrapping_test { + ($fn_name:ident, $type:ty, $min:expr, $max:expr) => { + #[test] + fn $fn_name() { + let zero: Wrapping<$type> = Wrapping(0); + let one: Wrapping<$type> = Wrapping(1); + let min: Wrapping<$type> = Wrapping($min); + let max: Wrapping<$type> = Wrapping($max); + + wrapping_operation!(min, max + one); + wrapping_assignment!(min, max += one); + wrapping_operation!(max, min - one); + wrapping_assignment!(max, min -= one); + wrapping_operation!(max, max * one); + wrapping_assignment!(max, max *= one); + wrapping_operation!(max, max / one); + wrapping_assignment!(max, max /= one); + wrapping_operation!(zero, max % one); + wrapping_assignment!(zero, max %= one); + wrapping_operation!(zero, zero & max); + wrapping_assignment!(zero, zero &= max); + wrapping_operation!(max, zero | max); + wrapping_assignment!(max, zero |= max); + wrapping_operation!(zero, max ^ max); + wrapping_assignment!(zero, max ^= max); + wrapping_operation!(zero, zero << 1usize); + wrapping_assignment!(zero, zero <<= 1usize); + wrapping_operation!(zero, zero >> 1usize); + wrapping_assignment!(zero, zero >>= 1usize); + wrapping_operation!(zero, -zero); + wrapping_operation!(max, !min); + } + }; +} + +wrapping_test!(test_wrapping_i8, i8, i8::MIN, i8::MAX); +wrapping_test!(test_wrapping_i16, i16, i16::MIN, i16::MAX); +wrapping_test!(test_wrapping_i32, i32, i32::MIN, i32::MAX); +wrapping_test!(test_wrapping_i64, i64, i64::MIN, i64::MAX); +wrapping_test!(test_wrapping_i128, i128, i128::MIN, i128::MAX); +wrapping_test!(test_wrapping_isize, isize, isize::MIN, isize::MAX); +wrapping_test!(test_wrapping_u8, u8, u8::MIN, u8::MAX); +wrapping_test!(test_wrapping_u16, u16, u16::MIN, u16::MAX); +wrapping_test!(test_wrapping_u32, u32, u32::MIN, u32::MAX); +wrapping_test!(test_wrapping_u64, u64, u64::MIN, u64::MAX); +wrapping_test!(test_wrapping_u128, u128, u128::MIN, u128::MAX); +wrapping_test!(test_wrapping_usize, usize, usize::MIN, usize::MAX); + +#[test] +fn wrapping_int_api() { + assert_eq!(i8::MAX.wrapping_add(1), i8::MIN); + assert_eq!(i16::MAX.wrapping_add(1), i16::MIN); + assert_eq!(i32::MAX.wrapping_add(1), i32::MIN); + assert_eq!(i64::MAX.wrapping_add(1), i64::MIN); + assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); + + assert_eq!(i8::MIN.wrapping_sub(1), i8::MAX); + assert_eq!(i16::MIN.wrapping_sub(1), i16::MAX); + assert_eq!(i32::MIN.wrapping_sub(1), i32::MAX); + assert_eq!(i64::MIN.wrapping_sub(1), i64::MAX); + assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); + + assert_eq!(u8::MAX.wrapping_add(1), u8::MIN); + assert_eq!(u16::MAX.wrapping_add(1), u16::MIN); + assert_eq!(u32::MAX.wrapping_add(1), u32::MIN); + assert_eq!(u64::MAX.wrapping_add(1), u64::MIN); + assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); + + assert_eq!(u8::MIN.wrapping_sub(1), u8::MAX); + assert_eq!(u16::MIN.wrapping_sub(1), u16::MAX); + assert_eq!(u32::MIN.wrapping_sub(1), u32::MAX); + assert_eq!(u64::MIN.wrapping_sub(1), u64::MAX); + assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); + + assert_eq!((0xfe_u8 as i8).wrapping_mul(16), (0xe0_u8 as i8)); + assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), (0xedc0_u16 as i16)); + assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), (0xedcb_a980_u32 as i32)); + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as i64) + ); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), (0xedcb_a980_u32 as isize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as isize) + ); + } + } + + assert_eq!((0xfe as u8).wrapping_mul(16), (0xe0 as u8)); + assert_eq!((0xfedc as u16).wrapping_mul(16), (0xedc0 as u16)); + assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), (0xedcb_a980 as u32)); + assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), (0xedcb_a987_6543_2170 as u64)); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), (0xedcb_a980 as usize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), + (0xedcb_a987_6543_2170 as usize) + ); + } + } + + macro_rules! check_mul_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), ($e) * $f); + }; + } + macro_rules! check_mul_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), $e); + }; + } + + check_mul_no_wrap!(0xfe_u8 as i8, -1); + check_mul_no_wrap!(0xfedc_u16 as i16, -1); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_mul_no_wrap!(0xfe_u8 as i8, -2); + check_mul_no_wrap!(0xfedc_u16 as i16, -2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); + + check_mul_no_wrap!(0xfe_u8 as i8, 2); + check_mul_no_wrap!(0xfedc_u16 as i16, 2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); + + check_mul_wraps!(0x80_u8 as i8, -1); + check_mul_wraps!(0x8000_u16 as i16, -1); + check_mul_wraps!(0x8000_0000_u32 as i32, -1); + check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_mul_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_div_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), ($e) / $f); + }; + } + macro_rules! check_div_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), $e); + }; + } + + check_div_no_wrap!(0xfe_u8 as i8, -1); + check_div_no_wrap!(0xfedc_u16 as i16, -1); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_div_no_wrap!(0xfe_u8 as i8, -2); + check_div_no_wrap!(0xfedc_u16 as i16, -2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_div_no_wrap!(0xfe_u8 as i8, 2); + check_div_no_wrap!(0xfedc_u16 as i16, 2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_div_wraps!(-128 as i8, -1); + check_div_wraps!(0x8000_u16 as i16, -1); + check_div_wraps!(0x8000_0000_u32 as i32, -1); + check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_div_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_rem_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), ($e) % $f); + }; + } + macro_rules! check_rem_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), 0); + }; + } + + check_rem_no_wrap!(0xfe_u8 as i8, -1); + check_rem_no_wrap!(0xfedc_u16 as i16, -1); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_rem_no_wrap!(0xfe_u8 as i8, -2); + check_rem_no_wrap!(0xfedc_u16 as i16, -2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_rem_no_wrap!(0xfe_u8 as i8, 2); + check_rem_no_wrap!(0xfedc_u16 as i16, 2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_rem_wraps!(0x80_u8 as i8, -1); + check_rem_wraps!(0x8000_u16 as i16, -1); + check_rem_wraps!(0x8000_0000_u32 as i32, -1); + check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_rem_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_neg_no_wrap { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), -($e)); + }; + } + macro_rules! check_neg_wraps { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), ($e)); + }; + } + + check_neg_no_wrap!(0xfe_u8 as i8); + check_neg_no_wrap!(0xfedc_u16 as i16); + check_neg_no_wrap!(0xfedc_ba98_u32 as i32); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); + + check_neg_wraps!(0x80_u8 as i8); + check_neg_wraps!(0x8000_u16 as i16); + check_neg_wraps!(0x8000_0000_u32 as i32); + check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_neg_wraps!(0x8000_0000_u32 as isize); + } + #[cfg(target_pointer_width = "64")] + () => { + check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); + } + } +} + +#[test] +fn wrapping_const() { + // Specifically the wrapping behavior of division and remainder is subtle, + // see https://github.com/rust-lang/rust/pull/94512. + const _: () = { + assert!(i32::MIN.wrapping_div(-1) == i32::MIN); + assert!(i32::MIN.wrapping_rem(-1) == 0); + }; +} diff --git a/library/coretests/tests/ops.rs b/library/coretests/tests/ops.rs new file mode 100644 index 00000000000..501e0f33fe4 --- /dev/null +++ b/library/coretests/tests/ops.rs @@ -0,0 +1,242 @@ +mod control_flow; +mod from_residual; + +use core::ops::{ + Bound, Deref, DerefMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, +}; + +// Test the Range structs and syntax. + +#[test] +fn test_range() { + let r = Range { start: 2, end: 10 }; + let mut count = 0; + for (i, ri) in r.enumerate() { + assert_eq!(ri, i + 2); + assert!(ri >= 2 && ri < 10); + count += 1; + } + assert_eq!(count, 8); +} + +#[test] +fn test_range_from() { + let r = RangeFrom { start: 2 }; + let mut count = 0; + for (i, ri) in r.take(10).enumerate() { + assert_eq!(ri, i + 2); + assert!(ri >= 2 && ri < 12); + count += 1; + } + assert_eq!(count, 10); +} + +#[test] +fn test_range_to() { + // Not much to test. + let _ = RangeTo { end: 42 }; +} + +#[test] +fn test_full_range() { + // Not much to test. + let _ = RangeFull; +} + +#[test] +fn test_range_inclusive() { + let mut r = RangeInclusive::new(1i8, 2); + assert_eq!(r.next(), Some(1)); + assert_eq!(r.next(), Some(2)); + assert_eq!(r.next(), None); + + r = RangeInclusive::new(127i8, 127); + assert_eq!(r.next(), Some(127)); + assert_eq!(r.next(), None); + + r = RangeInclusive::new(-128i8, -128); + assert_eq!(r.next_back(), Some(-128)); + assert_eq!(r.next_back(), None); + + // degenerate + r = RangeInclusive::new(1, -1); + assert_eq!(r.size_hint(), (0, Some(0))); + assert_eq!(r.next(), None); +} + +#[test] +fn test_range_to_inclusive() { + // Not much to test. + let _ = RangeToInclusive { end: 42 }; +} + +#[test] +fn test_range_is_empty() { + assert!(!(0.0..10.0).is_empty()); + assert!((-0.0..0.0).is_empty()); + assert!((10.0..0.0).is_empty()); + + assert!(!(f32::NEG_INFINITY..f32::INFINITY).is_empty()); + assert!((f32::EPSILON..f32::NAN).is_empty()); + assert!((f32::NAN..f32::EPSILON).is_empty()); + assert!((f32::NAN..f32::NAN).is_empty()); + + assert!(!(0.0..=10.0).is_empty()); + assert!(!(-0.0..=0.0).is_empty()); + assert!((10.0..=0.0).is_empty()); + + assert!(!(f32::NEG_INFINITY..=f32::INFINITY).is_empty()); + assert!((f32::EPSILON..=f32::NAN).is_empty()); + assert!((f32::NAN..=f32::EPSILON).is_empty()); + assert!((f32::NAN..=f32::NAN).is_empty()); +} + +#[test] +fn test_bound_cloned_unbounded() { + assert_eq!(Bound::<&u32>::Unbounded.cloned(), Bound::Unbounded); +} + +#[test] +fn test_bound_cloned_included() { + assert_eq!(Bound::Included(&3).cloned(), Bound::Included(3)); +} + +#[test] +fn test_bound_cloned_excluded() { + assert_eq!(Bound::Excluded(&3).cloned(), Bound::Excluded(3)); +} + +#[test] +#[allow(unused_comparisons)] +#[allow(unused_mut)] +fn test_range_syntax() { + let mut count = 0; + for i in 0_usize..10 { + assert!(i >= 0 && i < 10); + count += i; + } + assert_eq!(count, 45); + + let mut count = 0; + let mut range = 0_usize..10; + for i in range { + assert!(i >= 0 && i < 10); + count += i; + } + assert_eq!(count, 45); + + let mut count = 0; + let mut rf = 3_usize..; + for i in rf.take(10) { + assert!(i >= 3 && i < 13); + count += i; + } + assert_eq!(count, 75); + + let _ = 0_usize..4 + 4 - 3; + + fn foo() -> isize { + 42 + } + let _ = 0..foo(); + + let _ = { &42..&100 }; // references to literals are OK + let _ = ..42_usize; + + // Test we can use two different types with a common supertype. + let x = &42; + { + let y = 42; + let _ = x..&y; + } +} + +#[test] +#[allow(dead_code)] +fn test_range_syntax_in_return_statement() { + fn return_range_to() -> RangeTo { + return ..1; + } + fn return_full_range() -> RangeFull { + return ..; + } + // Not much to test. +} + +#[test] +fn range_structural_match() { + // test that all range types can be structurally matched upon + + const RANGE: Range = 0..1000; + match RANGE { + RANGE => {} + _ => unreachable!(), + } + + const RANGE_FROM: RangeFrom = 0..; + match RANGE_FROM { + RANGE_FROM => {} + _ => unreachable!(), + } + + const RANGE_FULL: RangeFull = ..; + match RANGE_FULL { + RANGE_FULL => {} + } + + const RANGE_INCLUSIVE: RangeInclusive = 0..=999; + match RANGE_INCLUSIVE { + RANGE_INCLUSIVE => {} + _ => unreachable!(), + } + + const RANGE_TO: RangeTo = ..1000; + match RANGE_TO { + RANGE_TO => {} + _ => unreachable!(), + } + + const RANGE_TO_INCLUSIVE: RangeToInclusive = ..=999; + match RANGE_TO_INCLUSIVE { + RANGE_TO_INCLUSIVE => {} + _ => unreachable!(), + } +} + +// Test Deref implementations + +#[test] +fn deref_mut_on_ref() { + // Test that `&mut T` implements `DerefMut` + + fn inc + DerefMut>(mut t: T) { + *t += 1; + } + + let mut x: isize = 5; + inc(&mut x); + assert_eq!(x, 6); +} + +#[test] +fn deref_on_ref() { + // Test that `&T` and `&mut T` implement `Deref` + + fn deref>(t: T) -> U { + *t + } + + let x: isize = 3; + let y = deref(&x); + assert_eq!(y, 3); + + let mut x: isize = 4; + let y = deref(&mut x); + assert_eq!(y, 4); +} + +#[test] +#[allow(unreachable_code)] +fn test_not_never() { + if !return () {} +} diff --git a/library/coretests/tests/ops/control_flow.rs b/library/coretests/tests/ops/control_flow.rs new file mode 100644 index 00000000000..eacfd63a6c4 --- /dev/null +++ b/library/coretests/tests/ops/control_flow.rs @@ -0,0 +1,18 @@ +use core::intrinsics::discriminant_value; +use core::ops::ControlFlow; + +#[test] +fn control_flow_discriminants_match_result() { + // This isn't stable surface area, but helps keep `?` cheap between them, + // even if LLVM can't always take advantage of it right now. + // (Sadly Result and Option are inconsistent, so ControlFlow can't match both.) + + assert_eq!( + discriminant_value(&ControlFlow::::Break(3)), + discriminant_value(&Result::::Err(3)), + ); + assert_eq!( + discriminant_value(&ControlFlow::::Continue(3)), + discriminant_value(&Result::::Ok(3)), + ); +} diff --git a/library/coretests/tests/ops/from_residual.rs b/library/coretests/tests/ops/from_residual.rs new file mode 100644 index 00000000000..d5c86ccbcd3 --- /dev/null +++ b/library/coretests/tests/ops/from_residual.rs @@ -0,0 +1,26 @@ +//! Regression test that Option and ControlFlow can have downstream FromResidual impls. +//! cc https://github.com/rust-lang/rust/issues/99940, +//! This does NOT test that issue in general; Option and ControlFlow's FromResidual +//! impls in core were changed to not be affected by that issue. + +use core::ops::{ControlFlow, FromResidual}; + +struct Local; + +impl FromResidual for Option { + fn from_residual(_: Local) -> Option { + unimplemented!() + } +} + +impl FromResidual for ControlFlow { + fn from_residual(_: Local) -> ControlFlow { + unimplemented!() + } +} + +impl FromResidual for Result { + fn from_residual(_: Local) -> Result { + unimplemented!() + } +} diff --git a/library/coretests/tests/option.rs b/library/coretests/tests/option.rs new file mode 100644 index 00000000000..336a79a02ce --- /dev/null +++ b/library/coretests/tests/option.rs @@ -0,0 +1,586 @@ +use core::cell::Cell; +use core::mem; +use core::ops::DerefMut; +use core::option::*; + +#[test] +fn test_get_ptr() { + unsafe { + let x: Box<_> = Box::new(0); + let addr_x: *const isize = mem::transmute(&*x); + let opt = Some(x); + let y = opt.unwrap(); + let addr_y: *const isize = mem::transmute(&*y); + assert_eq!(addr_x, addr_y); + } +} + +#[test] +fn test_get_str() { + let x = "test".to_string(); + let addr_x = x.as_ptr(); + let opt = Some(x); + let y = opt.unwrap(); + let addr_y = y.as_ptr(); + assert_eq!(addr_x, addr_y); +} + +#[test] +fn test_get_resource() { + use core::cell::RefCell; + use std::rc::Rc; + + struct R { + i: Rc>, + } + + impl Drop for R { + fn drop(&mut self) { + let ii = &*self.i; + let i = *ii.borrow(); + *ii.borrow_mut() = i + 1; + } + } + + fn r(i: Rc>) -> R { + R { i } + } + + let i = Rc::new(RefCell::new(0)); + { + let x = r(i.clone()); + let opt = Some(x); + let _y = opt.unwrap(); + } + assert_eq!(*i.borrow(), 1); +} + +#[test] +#[allow(for_loops_over_fallibles)] +fn test_option_dance() { + let x = Some(()); + let mut y = Some(5); + let mut y2 = 0; + for _x in x { + y2 = y.take().unwrap(); + } + assert_eq!(y2, 5); + assert!(y.is_none()); +} + +#[test] +#[should_panic] +fn test_option_too_much_dance() { + struct A; + let mut y = Some(A); + let _y2 = y.take().unwrap(); + let _y3 = y.take().unwrap(); +} + +#[test] +fn test_and() { + let x: Option = Some(1); + assert_eq!(x.and(Some(2)), Some(2)); + assert_eq!(x.and(None::), None); + + let x: Option = None; + assert_eq!(x.and(Some(2)), None); + assert_eq!(x.and(None::), None); + + /* FIXME(#110395) + const FOO: Option = Some(1); + const A: Option = FOO.and(Some(2)); + const B: Option = FOO.and(None); + assert_eq!(A, Some(2)); + assert_eq!(B, None); + + const BAR: Option = None; + const C: Option = BAR.and(Some(2)); + const D: Option = BAR.and(None); + assert_eq!(C, None); + assert_eq!(D, None); + */ +} + +#[test] +fn test_and_then() { + const fn plus_one(x: isize) -> Option { + Some(x + 1) + } + + const fn none(_: isize) -> Option { + None + } + + let x: Option = Some(1); + assert_eq!(x.and_then(plus_one), Some(2)); + assert_eq!(x.and_then(none), None); + + let x: Option = None; + assert_eq!(x.and_then(plus_one), None); + assert_eq!(x.and_then(none), None); + + /* FIXME(#110395) + const FOO: Option = Some(1); + const A: Option = FOO.and_then(plus_one); + const B: Option = FOO.and_then(none); + assert_eq!(A, Some(2)); + assert_eq!(B, None); + + const BAR: Option = None; + const C: Option = BAR.and_then(plus_one); + const D: Option = BAR.and_then(none); + assert_eq!(C, None); + assert_eq!(D, None); + */ +} + +#[test] +fn test_or() { + let x: Option = Some(1); + assert_eq!(x.or(Some(2)), Some(1)); + assert_eq!(x.or(None), Some(1)); + + let x: Option = None; + assert_eq!(x.or(Some(2)), Some(2)); + assert_eq!(x.or(None), None); + + /* FIXME(#110395) + const FOO: Option = Some(1); + const A: Option = FOO.or(Some(2)); + const B: Option = FOO.or(None); + assert_eq!(A, Some(1)); + assert_eq!(B, Some(1)); + + const BAR: Option = None; + const C: Option = BAR.or(Some(2)); + const D: Option = BAR.or(None); + assert_eq!(C, Some(2)); + assert_eq!(D, None); + */ +} + +#[test] +fn test_or_else() { + const fn two() -> Option { + Some(2) + } + + const fn none() -> Option { + None + } + + let x: Option = Some(1); + assert_eq!(x.or_else(two), Some(1)); + assert_eq!(x.or_else(none), Some(1)); + + let x: Option = None; + assert_eq!(x.or_else(two), Some(2)); + assert_eq!(x.or_else(none), None); + + /* FIXME(#110395) + const FOO: Option = Some(1); + const A: Option = FOO.or_else(two); + const B: Option = FOO.or_else(none); + assert_eq!(A, Some(1)); + assert_eq!(B, Some(1)); + + const BAR: Option = None; + const C: Option = BAR.or_else(two); + const D: Option = BAR.or_else(none); + assert_eq!(C, Some(2)); + assert_eq!(D, None); + */ +} + +#[test] +fn test_unwrap() { + assert_eq!(Some(1).unwrap(), 1); + let s = Some("hello".to_string()).unwrap(); + assert_eq!(s, "hello"); +} + +#[test] +#[should_panic] +fn test_unwrap_panic1() { + let x: Option = None; + x.unwrap(); +} + +#[test] +#[should_panic] +fn test_unwrap_panic2() { + let x: Option = None; + x.unwrap(); +} + +#[test] +fn test_unwrap_or() { + let x: Option = Some(1); + assert_eq!(x.unwrap_or(2), 1); + + let x: Option = None; + assert_eq!(x.unwrap_or(2), 2); + + /* FIXME(#110395) + const A: isize = Some(1).unwrap_or(2); + const B: isize = None.unwrap_or(2); + assert_eq!(A, 1); + assert_eq!(B, 2); + */ +} + +#[test] +fn test_unwrap_or_else() { + const fn two() -> isize { + 2 + } + + let x: Option = Some(1); + assert_eq!(x.unwrap_or_else(two), 1); + + let x: Option = None; + assert_eq!(x.unwrap_or_else(two), 2); + + /* FIXME(#110395) + const A: isize = Some(1).unwrap_or_else(two); + const B: isize = None.unwrap_or_else(two); + assert_eq!(A, 1); + assert_eq!(B, 2); + */ +} + +#[test] +fn test_unwrap_unchecked() { + assert_eq!(unsafe { Some(1).unwrap_unchecked() }, 1); + let s = unsafe { Some("hello".to_string()).unwrap_unchecked() }; + assert_eq!(s, "hello"); +} + +#[test] +fn test_iter() { + let val = 5; + + let x = Some(val); + let mut it = x.iter(); + + assert_eq!(it.size_hint(), (1, Some(1))); + assert_eq!(it.next(), Some(&val)); + assert_eq!(it.size_hint(), (0, Some(0))); + assert!(it.next().is_none()); + + let mut it = (&x).into_iter(); + assert_eq!(it.next(), Some(&val)); +} + +#[test] +fn test_mut_iter() { + let mut val = 5; + let new_val = 11; + + let mut x = Some(val); + { + let mut it = x.iter_mut(); + + assert_eq!(it.size_hint(), (1, Some(1))); + + match it.next() { + Some(interior) => { + assert_eq!(*interior, val); + *interior = new_val; + } + None => assert!(false), + } + + assert_eq!(it.size_hint(), (0, Some(0))); + assert!(it.next().is_none()); + } + assert_eq!(x, Some(new_val)); + + let mut y = Some(val); + let mut it = (&mut y).into_iter(); + assert_eq!(it.next(), Some(&mut val)); +} + +#[test] +fn test_ord() { + let small = Some(1.0f64); + let big = Some(5.0f64); + let nan = Some(0.0f64 / 0.0); + assert!(!(nan < big)); + assert!(!(nan > big)); + assert!(small < big); + assert!(None < big); + assert!(big > None); +} + +#[test] +fn test_collect() { + let v: Option> = (0..0).map(|_| Some(0)).collect(); + assert!(v == Some(vec![])); + + let v: Option> = (0..3).map(|x| Some(x)).collect(); + assert!(v == Some(vec![0, 1, 2])); + + let v: Option> = (0..3).map(|x| if x > 1 { None } else { Some(x) }).collect(); + assert!(v == None); + + // test that it does not take more elements than it needs + let mut functions: [Box Option<()>>; 3] = + [Box::new(|| Some(())), Box::new(|| None), Box::new(|| panic!())]; + + let v: Option> = functions.iter_mut().map(|f| (*f)()).collect(); + + assert!(v == None); +} + +#[test] +fn test_copied() { + let val = 1; + let val_ref = &val; + let opt_none: Option<&'static u32> = None; + let opt_ref = Some(&val); + let opt_ref_ref = Some(&val_ref); + + // None works + assert_eq!(opt_none.clone(), None); + assert_eq!(opt_none.copied(), None); + + // Immutable ref works + assert_eq!(opt_ref.clone(), Some(&val)); + assert_eq!(opt_ref.copied(), Some(1)); + + // Double Immutable ref works + assert_eq!(opt_ref_ref.clone(), Some(&val_ref)); + assert_eq!(opt_ref_ref.clone().copied(), Some(&val)); + assert_eq!(opt_ref_ref.copied().copied(), Some(1)); +} + +#[test] +fn test_cloned() { + let val = 1; + let val_ref = &val; + let opt_none: Option<&'static u32> = None; + let opt_ref = Some(&val); + let opt_ref_ref = Some(&val_ref); + + // None works + assert_eq!(opt_none.clone(), None); + assert_eq!(opt_none.cloned(), None); + + // Immutable ref works + assert_eq!(opt_ref.clone(), Some(&val)); + assert_eq!(opt_ref.cloned(), Some(1)); + + // Double Immutable ref works + assert_eq!(opt_ref_ref.clone(), Some(&val_ref)); + assert_eq!(opt_ref_ref.clone().cloned(), Some(&val)); + assert_eq!(opt_ref_ref.cloned().cloned(), Some(1)); +} + +#[test] +fn test_try() { + fn try_option_some() -> Option { + let val = Some(1)?; + Some(val) + } + assert_eq!(try_option_some(), Some(1)); + + fn try_option_none() -> Option { + let val = None?; + Some(val) + } + assert_eq!(try_option_none(), None); +} + +#[test] +fn test_option_as_deref() { + // Some: &Option::Some(T) -> Option<&T::Deref::Target>::Some(&*T) + let ref_option = &Some(&42); + assert_eq!(ref_option.as_deref(), Some(&42)); + + let ref_option = &Some(String::from("a result")); + assert_eq!(ref_option.as_deref(), Some("a result")); + + let ref_option = &Some(vec![1, 2, 3, 4, 5]); + assert_eq!(ref_option.as_deref(), Some([1, 2, 3, 4, 5].as_slice())); + + // None: &Option>::None -> None + let ref_option: &Option<&i32> = &None; + assert_eq!(ref_option.as_deref(), None); +} + +#[test] +fn test_option_as_deref_mut() { + // Some: &mut Option::Some(T) -> Option<&mut T::Deref::Target>::Some(&mut *T) + let mut val = 42; + let ref_option = &mut Some(&mut val); + assert_eq!(ref_option.as_deref_mut(), Some(&mut 42)); + + let ref_option = &mut Some(String::from("a result")); + assert_eq!(ref_option.as_deref_mut(), Some(String::from("a result").deref_mut())); + + let ref_option = &mut Some(vec![1, 2, 3, 4, 5]); + assert_eq!(ref_option.as_deref_mut(), Some([1, 2, 3, 4, 5].as_mut_slice())); + + // None: &mut Option>::None -> None + let ref_option: &mut Option<&mut i32> = &mut None; + assert_eq!(ref_option.as_deref_mut(), None); +} + +#[test] +fn test_replace() { + let mut x = Some(2); + let old = x.replace(5); + + assert_eq!(x, Some(5)); + assert_eq!(old, Some(2)); + + let mut x = None; + let old = x.replace(3); + + assert_eq!(x, Some(3)); + assert_eq!(old, None); +} + +#[test] +fn option_const() { + // test that the methods of `Option` are usable in a const context + + const OPTION: Option = Some(32); + assert_eq!(OPTION, Some(32)); + + // FIXME(#110395) + // const OPTION_FROM: Option = Option::from(32); + // assert_eq!(OPTION_FROM, Some(32)); + + const REF: Option<&usize> = OPTION.as_ref(); + assert_eq!(REF, Some(&32)); + + // const REF_FROM: Option<&usize> = Option::from(&OPTION); + // assert_eq!(REF_FROM, Some(&32)); + + const IS_SOME: bool = OPTION.is_some(); + assert!(IS_SOME); + + const IS_NONE: bool = OPTION.is_none(); + assert!(!IS_NONE); + + const COPIED: Option = OPTION.as_ref().copied(); + assert_eq!(COPIED, OPTION); +} + +#[test] +const fn option_const_mut() { + // test that the methods of `Option` that take mutable references are usable in a const context + + let mut option: Option = Some(32); + + let _take = option.take(); + let _replace = option.replace(42); + + { + let as_mut = option.as_mut(); + match as_mut { + Some(v) => *v = 32, + None => unreachable!(), + } + } + /* FIXME(const-hack) + { + let as_mut: Option<&mut usize> = Option::from(&mut option); + match as_mut { + Some(v) => *v = 42, + None => unreachable!(), + } + } + */ +} + +#[test] +fn test_unwrap_drop() { + struct Dtor<'a> { + x: &'a Cell, + } + + impl<'a> std::ops::Drop for Dtor<'a> { + fn drop(&mut self) { + self.x.set(self.x.get() - 1); + } + } + + fn unwrap(o: Option) -> T { + match o { + Some(v) => v, + None => panic!(), + } + } + + let x = &Cell::new(1); + + { + let b = Some(Dtor { x }); + let _c = unwrap(b); + } + + assert_eq!(x.get(), 0); +} + +#[test] +fn option_ext() { + let thing = "{{ f }}"; + let f = thing.find("{{"); + + if f.is_none() { + println!("None!"); + } +} + +#[test] +fn zip_options() { + let x = Some(10); + let y = Some("foo"); + let z: Option = None; + + assert_eq!(x.zip(y), Some((10, "foo"))); + assert_eq!(x.zip(z), None); + assert_eq!(z.zip(x), None); +} + +#[test] +fn unzip_options() { + let x = Some((10, "foo")); + let y = None::<(bool, i32)>; + + assert_eq!(x.unzip(), (Some(10), Some("foo"))); + assert_eq!(y.unzip(), (None, None)); +} + +#[test] +fn zip_unzip_roundtrip() { + let x = Some(10); + let y = Some("foo"); + + let z = x.zip(y); + assert_eq!(z, Some((10, "foo"))); + + let a = z.unzip(); + assert_eq!(a, (x, y)); +} + +#[test] +fn as_slice() { + assert_eq!(Some(42).as_slice(), &[42]); + assert_eq!(Some(43).as_mut_slice(), &[43]); + assert_eq!(None::.as_slice(), &[]); + assert_eq!(None::.as_mut_slice(), &[]); + + const A: &[u32] = Some(44).as_slice(); + const B: &[u32] = None.as_slice(); + const _: () = { + let [45] = Some(45).as_mut_slice() else { panic!() }; + let []: &[u32] = None.as_mut_slice() else { panic!() }; + }; + assert_eq!(A, &[44]); + assert_eq!(B, &[]); +} diff --git a/library/coretests/tests/panic.rs b/library/coretests/tests/panic.rs new file mode 100644 index 00000000000..24b6c56b356 --- /dev/null +++ b/library/coretests/tests/panic.rs @@ -0,0 +1 @@ +mod location; diff --git a/library/coretests/tests/panic/location.rs b/library/coretests/tests/panic/location.rs new file mode 100644 index 00000000000..d20241d8380 --- /dev/null +++ b/library/coretests/tests/panic/location.rs @@ -0,0 +1,31 @@ +use core::panic::Location; + +// Note: Some of the following tests depend on the source location, +// so please be careful when editing this file. + +#[test] +fn location_const_caller() { + const _CALLER_REFERENCE: &Location<'static> = Location::caller(); + const _CALLER: Location<'static> = *Location::caller(); +} + +#[test] +fn location_const_file() { + const CALLER: &Location<'static> = Location::caller(); + const FILE: &str = CALLER.file(); + assert_eq!(FILE, file!()); +} + +#[test] +fn location_const_line() { + const CALLER: &Location<'static> = Location::caller(); + const LINE: u32 = CALLER.line(); + assert_eq!(LINE, 21); +} + +#[test] +fn location_const_column() { + const CALLER: &Location<'static> = Location::caller(); + const COLUMN: u32 = CALLER.column(); + assert_eq!(COLUMN, 40); +} diff --git a/library/coretests/tests/pattern.rs b/library/coretests/tests/pattern.rs new file mode 100644 index 00000000000..d4bec996d89 --- /dev/null +++ b/library/coretests/tests/pattern.rs @@ -0,0 +1,503 @@ +use std::str::pattern::*; + +// This macro makes it easier to write +// tests that do a series of iterations +macro_rules! search_asserts { + ($haystack:expr, $needle:expr, $testname:expr, [$($func:ident),*], $result:expr) => { + let mut searcher = $needle.into_searcher($haystack); + let arr = [$( Step::from(searcher.$func()) ),*]; + assert_eq!(&arr[..], &$result, $testname); + } +} + +/// Combined enum for the results of next() and next_match()/next_reject() +#[derive(Debug, PartialEq, Eq)] +enum Step { + // variant names purposely chosen to + // be the same length for easy alignment + Matches(usize, usize), + Rejects(usize, usize), + InRange(usize, usize), + Done, +} + +use self::Step::*; + +impl From for Step { + fn from(x: SearchStep) -> Self { + match x { + SearchStep::Match(a, b) => Matches(a, b), + SearchStep::Reject(a, b) => Rejects(a, b), + SearchStep::Done => Done, + } + } +} + +impl From> for Step { + fn from(x: Option<(usize, usize)>) -> Self { + match x { + Some((a, b)) => InRange(a, b), + None => Done, + } + } +} + +// FIXME(Manishearth) these tests focus on single-character searching (CharSearcher) +// and on next()/next_match(), not next_reject(). This is because +// the memchr changes make next_match() for single chars complex, but next_reject() +// continues to use next() under the hood. We should add more test cases for all +// of these, as well as tests for StrSearcher and higher level tests for str::find() (etc) + +#[test] +fn test_simple_iteration() { + search_asserts!( + "abcdeabcd", + 'a', + "forward iteration for ASCII string", + // a b c d e a b c d EOF + [next, next, next, next, next, next, next, next, next, next], + [ + Matches(0, 1), + Rejects(1, 2), + Rejects(2, 3), + Rejects(3, 4), + Rejects(4, 5), + Matches(5, 6), + Rejects(6, 7), + Rejects(7, 8), + Rejects(8, 9), + Done + ] + ); + + search_asserts!( + "abcdeabcd", + 'a', + "reverse iteration for ASCII string", + // d c b a e d c b a EOF + [ + next_back, next_back, next_back, next_back, next_back, next_back, next_back, next_back, + next_back, next_back + ], + [ + Rejects(8, 9), + Rejects(7, 8), + Rejects(6, 7), + Matches(5, 6), + Rejects(4, 5), + Rejects(3, 4), + Rejects(2, 3), + Rejects(1, 2), + Matches(0, 1), + Done + ] + ); + + search_asserts!( + "我爱我的猫", + '我', + "forward iteration for Chinese string", + // 我 愛 我 的 貓 EOF + [next, next, next, next, next, next], + [Matches(0, 3), Rejects(3, 6), Matches(6, 9), Rejects(9, 12), Rejects(12, 15), Done] + ); + + search_asserts!( + "我的猫说meow", + 'm', + "forward iteration for mixed string", + // 我 的 猫 说 m e o w EOF + [next, next, next, next, next, next, next, next, next], + [ + Rejects(0, 3), + Rejects(3, 6), + Rejects(6, 9), + Rejects(9, 12), + Matches(12, 13), + Rejects(13, 14), + Rejects(14, 15), + Rejects(15, 16), + Done + ] + ); + + search_asserts!( + "我的猫说meow", + '猫', + "reverse iteration for mixed string", + // w o e m 说 猫 的 我 EOF + [ + next_back, next_back, next_back, next_back, next_back, next_back, next_back, next_back, + next_back + ], + [ + Rejects(15, 16), + Rejects(14, 15), + Rejects(13, 14), + Rejects(12, 13), + Rejects(9, 12), + Matches(6, 9), + Rejects(3, 6), + Rejects(0, 3), + Done + ] + ); +} + +#[test] +fn test_simple_search() { + search_asserts!( + "abcdeabcdeabcde", + 'a', + "next_match for ASCII string", + [next_match, next_match, next_match, next_match], + [InRange(0, 1), InRange(5, 6), InRange(10, 11), Done] + ); + + search_asserts!( + "abcdeabcdeabcde", + 'a', + "next_match_back for ASCII string", + [next_match_back, next_match_back, next_match_back, next_match_back], + [InRange(10, 11), InRange(5, 6), InRange(0, 1), Done] + ); + + search_asserts!( + "abcdeab", + 'a', + "next_reject for ASCII string", + [next_reject, next_reject, next_match, next_reject, next_reject], + [InRange(1, 2), InRange(2, 3), InRange(5, 6), InRange(6, 7), Done] + ); + + search_asserts!( + "abcdeabcdeabcde", + 'a', + "next_reject_back for ASCII string", + [ + next_reject_back, + next_reject_back, + next_match_back, + next_reject_back, + next_reject_back, + next_reject_back + ], + [ + InRange(14, 15), + InRange(13, 14), + InRange(10, 11), + InRange(9, 10), + InRange(8, 9), + InRange(7, 8) + ] + ); +} + +// Á, 각, ก, 😀 all end in 0x81 +// 🁀, ᘀ do not end in 0x81 but contain the byte +// ꁁ has 0x81 as its second and third bytes. +// +// The memchr-using implementation of next_match +// and next_match_back temporarily violate +// the property that the search is always on a unicode boundary, +// which is fine as long as this never reaches next() or next_back(). +// So we test if next() is correct after each next_match() as well. +const STRESS: &str = "Áa🁀bÁꁁfg😁각กᘀ각aÁ각ꁁก😁a"; + +#[test] +fn test_stress_indices() { + // this isn't really a test, more of documentation on the indices of each character in the stresstest string + + search_asserts!( + STRESS, + 'x', + "Indices of characters in stress test", + [ + next, next, next, next, next, next, next, next, next, next, next, next, next, next, + next, next, next, next, next, next, next + ], + [ + Rejects(0, 2), // Á + Rejects(2, 3), // a + Rejects(3, 7), // 🁀 + Rejects(7, 8), // b + Rejects(8, 10), // Á + Rejects(10, 13), // ꁁ + Rejects(13, 14), // f + Rejects(14, 15), // g + Rejects(15, 19), // 😀 + Rejects(19, 22), // 각 + Rejects(22, 25), // ก + Rejects(25, 28), // ᘀ + Rejects(28, 31), // 각 + Rejects(31, 32), // a + Rejects(32, 34), // Á + Rejects(34, 37), // 각 + Rejects(37, 40), // ꁁ + Rejects(40, 43), // ก + Rejects(43, 47), // 😀 + Rejects(47, 48), // a + Done + ] + ); +} + +#[test] +fn test_forward_search_shared_bytes() { + search_asserts!( + STRESS, + 'Á', + "Forward search for two-byte Latin character", + [next_match, next_match, next_match, next_match], + [InRange(0, 2), InRange(8, 10), InRange(32, 34), Done] + ); + + search_asserts!( + STRESS, + 'Á', + "Forward search for two-byte Latin character; check if next() still works", + [next_match, next, next_match, next, next_match, next, next_match], + [ + InRange(0, 2), + Rejects(2, 3), + InRange(8, 10), + Rejects(10, 13), + InRange(32, 34), + Rejects(34, 37), + Done + ] + ); + + search_asserts!( + STRESS, + '각', + "Forward search for three-byte Hangul character", + [next_match, next, next_match, next_match, next_match], + [InRange(19, 22), Rejects(22, 25), InRange(28, 31), InRange(34, 37), Done] + ); + + search_asserts!( + STRESS, + '각', + "Forward search for three-byte Hangul character; check if next() still works", + [next_match, next, next_match, next, next_match, next, next_match], + [ + InRange(19, 22), + Rejects(22, 25), + InRange(28, 31), + Rejects(31, 32), + InRange(34, 37), + Rejects(37, 40), + Done + ] + ); + + search_asserts!( + STRESS, + 'ก', + "Forward search for three-byte Thai character", + [next_match, next, next_match, next, next_match], + [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done] + ); + + search_asserts!( + STRESS, + 'ก', + "Forward search for three-byte Thai character; check if next() still works", + [next_match, next, next_match, next, next_match], + [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done] + ); + + search_asserts!( + STRESS, + '😁', + "Forward search for four-byte emoji", + [next_match, next, next_match, next, next_match], + [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done] + ); + + search_asserts!( + STRESS, + '😁', + "Forward search for four-byte emoji; check if next() still works", + [next_match, next, next_match, next, next_match], + [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done] + ); + + search_asserts!( + STRESS, + 'ꁁ', + "Forward search for three-byte Yi character with repeated bytes", + [next_match, next, next_match, next, next_match], + [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done] + ); + + search_asserts!( + STRESS, + 'ꁁ', + "Forward search for three-byte Yi character with repeated bytes; check if next() still works", + [next_match, next, next_match, next, next_match], + [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done] + ); +} + +#[test] +fn test_reverse_search_shared_bytes() { + search_asserts!( + STRESS, + 'Á', + "Reverse search for two-byte Latin character", + [next_match_back, next_match_back, next_match_back, next_match_back], + [InRange(32, 34), InRange(8, 10), InRange(0, 2), Done] + ); + + search_asserts!( + STRESS, + 'Á', + "Reverse search for two-byte Latin character; check if next_back() still works", + [next_match_back, next_back, next_match_back, next_back, next_match_back, next_back], + [InRange(32, 34), Rejects(31, 32), InRange(8, 10), Rejects(7, 8), InRange(0, 2), Done] + ); + + search_asserts!( + STRESS, + '각', + "Reverse search for three-byte Hangul character", + [next_match_back, next_back, next_match_back, next_match_back, next_match_back], + [InRange(34, 37), Rejects(32, 34), InRange(28, 31), InRange(19, 22), Done] + ); + + search_asserts!( + STRESS, + '각', + "Reverse search for three-byte Hangul character; check if next_back() still works", + [ + next_match_back, + next_back, + next_match_back, + next_back, + next_match_back, + next_back, + next_match_back + ], + [ + InRange(34, 37), + Rejects(32, 34), + InRange(28, 31), + Rejects(25, 28), + InRange(19, 22), + Rejects(15, 19), + Done + ] + ); + + search_asserts!( + STRESS, + 'ก', + "Reverse search for three-byte Thai character", + [next_match_back, next_back, next_match_back, next_back, next_match_back], + [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done] + ); + + search_asserts!( + STRESS, + 'ก', + "Reverse search for three-byte Thai character; check if next_back() still works", + [next_match_back, next_back, next_match_back, next_back, next_match_back], + [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done] + ); + + search_asserts!( + STRESS, + '😁', + "Reverse search for four-byte emoji", + [next_match_back, next_back, next_match_back, next_back, next_match_back], + [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done] + ); + + search_asserts!( + STRESS, + '😁', + "Reverse search for four-byte emoji; check if next_back() still works", + [next_match_back, next_back, next_match_back, next_back, next_match_back], + [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done] + ); + + search_asserts!( + STRESS, + 'ꁁ', + "Reverse search for three-byte Yi character with repeated bytes", + [next_match_back, next_back, next_match_back, next_back, next_match_back], + [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done] + ); + + search_asserts!( + STRESS, + 'ꁁ', + "Reverse search for three-byte Yi character with repeated bytes; check if next_back() still works", + [next_match_back, next_back, next_match_back, next_back, next_match_back], + [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done] + ); +} + +#[test] +fn double_ended_regression_test() { + // https://github.com/rust-lang/rust/issues/47175 + // Ensures that double ended searching comes to a convergence + search_asserts!( + "abcdeabcdeabcde", + 'a', + "alternating double ended search", + [next_match, next_match_back, next_match, next_match_back], + [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done] + ); + search_asserts!( + "abcdeabcdeabcde", + 'a', + "triple double ended search for a", + [next_match, next_match_back, next_match_back, next_match_back], + [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done] + ); + search_asserts!( + "abcdeabcdeabcde", + 'd', + "triple double ended search for d", + [next_match, next_match_back, next_match_back, next_match_back], + [InRange(3, 4), InRange(13, 14), InRange(8, 9), Done] + ); + search_asserts!( + STRESS, + 'Á', + "Double ended search for two-byte Latin character", + [next_match, next_match_back, next_match, next_match_back], + [InRange(0, 2), InRange(32, 34), InRange(8, 10), Done] + ); + search_asserts!( + STRESS, + '각', + "Reverse double ended search for three-byte Hangul character", + [next_match_back, next_back, next_match, next, next_match_back, next_match], + [InRange(34, 37), Rejects(32, 34), InRange(19, 22), Rejects(22, 25), InRange(28, 31), Done] + ); + search_asserts!( + STRESS, + 'ก', + "Double ended search for three-byte Thai character", + [next_match, next_back, next, next_match_back, next_match], + [InRange(22, 25), Rejects(47, 48), Rejects(25, 28), InRange(40, 43), Done] + ); + search_asserts!( + STRESS, + '😁', + "Double ended search for four-byte emoji", + [next_match_back, next, next_match, next_back, next_match], + [InRange(43, 47), Rejects(0, 2), InRange(15, 19), Rejects(40, 43), Done] + ); + search_asserts!( + STRESS, + 'ꁁ', + "Double ended search for three-byte Yi character with repeated bytes", + [next_match, next, next_match_back, next_back, next_match], + [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(34, 37), Done] + ); +} diff --git a/library/coretests/tests/pin.rs b/library/coretests/tests/pin.rs new file mode 100644 index 00000000000..026d2ca8de2 --- /dev/null +++ b/library/coretests/tests/pin.rs @@ -0,0 +1,81 @@ +use core::pin::Pin; + +#[test] +fn pin_const() { + // test that the methods of `Pin` are usable in a const context + + const POINTER: &'static usize = &2; + + const PINNED: Pin<&'static usize> = Pin::new(POINTER); + const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) }; + assert_eq!(PINNED_UNCHECKED, PINNED); + + const INNER: &'static usize = Pin::into_inner(PINNED); + assert_eq!(INNER, POINTER); + + const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) }; + assert_eq!(INNER_UNCHECKED, POINTER); + + const REF: &'static usize = PINNED.get_ref(); + assert_eq!(REF, POINTER); + + const INT: u8 = 42; + const STATIC_REF: Pin<&'static u8> = Pin::static_ref(&INT); + assert_eq!(*STATIC_REF, INT); + + // Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context. + // A const fn is used because `&mut` is not (yet) usable in constants. + const fn pin_mut_const() { + let _ = Pin::new(&mut 2).into_ref(); + let _ = Pin::new(&mut 2).get_mut(); + let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() }; + } + + pin_mut_const(); +} + +#[allow(unused)] +mod pin_coerce_unsized { + use core::cell::{Cell, RefCell, UnsafeCell}; + use core::pin::Pin; + use core::ptr::NonNull; + + pub trait MyTrait {} + impl MyTrait for String {} + + // These Pins should continue to compile. + // Do note that these instances of Pin types cannot be used + // meaningfully because all methods require a Deref/DerefMut + // bounds on the pointer type and Cell, RefCell and UnsafeCell + // do not implement Deref/DerefMut. + + pub fn cell(arg: Pin>>) -> Pin>> { + arg + } + pub fn ref_cell(arg: Pin>>) -> Pin>> { + arg + } + pub fn unsafe_cell(arg: Pin>>) -> Pin>> { + arg + } + + // These sensible Pin coercions are possible. + pub fn pin_mut_ref(arg: Pin<&mut String>) -> Pin<&mut dyn MyTrait> { + arg + } + pub fn pin_ref(arg: Pin<&String>) -> Pin<&dyn MyTrait> { + arg + } + pub fn pin_ptr(arg: Pin<*const String>) -> Pin<*const dyn MyTrait> { + arg + } + pub fn pin_ptr_mut(arg: Pin<*mut String>) -> Pin<*mut dyn MyTrait> { + arg + } + pub fn pin_non_null(arg: Pin>) -> Pin> { + arg + } + pub fn nesting_pins(arg: Pin>) -> Pin> { + arg + } +} diff --git a/library/coretests/tests/pin_macro.rs b/library/coretests/tests/pin_macro.rs new file mode 100644 index 00000000000..43542397a61 --- /dev/null +++ b/library/coretests/tests/pin_macro.rs @@ -0,0 +1,32 @@ +// edition:2021 + +use core::marker::PhantomPinned; +use core::mem::{drop as stuff, transmute}; +use core::pin::{Pin, pin}; + +#[test] +fn basic() { + let it: Pin<&mut PhantomPinned> = pin!(PhantomPinned); + stuff(it); +} + +#[test] +fn extension_works_through_block() { + let it: Pin<&mut PhantomPinned> = { pin!(PhantomPinned) }; + stuff(it); +} + +#[test] +fn extension_works_through_unsafe_block() { + // "retro-type-inference" works as well. + let it: Pin<&mut PhantomPinned> = unsafe { pin!(transmute(())) }; + stuff(it); +} + +#[test] +fn unsize_coercion() { + let slice: Pin<&mut [PhantomPinned]> = pin!([PhantomPinned; 2]); + stuff(slice); + let dyn_obj: Pin<&mut dyn Send> = pin!([PhantomPinned; 2]); + stuff(dyn_obj); +} diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs new file mode 100644 index 00000000000..7cefb615d03 --- /dev/null +++ b/library/coretests/tests/ptr.rs @@ -0,0 +1,994 @@ +use core::cell::RefCell; +use core::marker::Freeze; +use core::mem::{self, MaybeUninit}; +use core::num::NonZero; +use core::ptr; +use core::ptr::*; +use std::fmt::{Debug, Display}; + +#[test] +fn test_const_from_raw_parts() { + const SLICE: &[u8] = &[1, 2, 3, 4]; + const FROM_RAW: &[u8] = unsafe { &*slice_from_raw_parts(SLICE.as_ptr(), SLICE.len()) }; + assert_eq!(SLICE, FROM_RAW); + + let slice = &[1, 2, 3, 4, 5]; + let from_raw = unsafe { &*slice_from_raw_parts(slice.as_ptr(), 2) }; + assert_eq!(&slice[..2], from_raw); +} + +#[test] +fn test() { + unsafe { + #[repr(C)] + struct Pair { + fst: isize, + snd: isize, + } + let mut p = Pair { fst: 10, snd: 20 }; + let pptr: *mut Pair = addr_of_mut!(p); + let iptr: *mut isize = pptr as *mut isize; + assert_eq!(*iptr, 10); + *iptr = 30; + assert_eq!(*iptr, 30); + assert_eq!(p.fst, 30); + + *pptr = Pair { fst: 50, snd: 60 }; + assert_eq!(*iptr, 50); + assert_eq!(p.fst, 50); + assert_eq!(p.snd, 60); + + let v0 = vec![32000u16, 32001u16, 32002u16]; + let mut v1 = vec![0u16, 0u16, 0u16]; + + copy(v0.as_ptr().offset(1), v1.as_mut_ptr().offset(1), 1); + assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16)); + copy(v0.as_ptr().offset(2), v1.as_mut_ptr(), 1); + assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16)); + copy(v0.as_ptr(), v1.as_mut_ptr().offset(2), 1); + assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16)); + } +} + +#[test] +fn test_is_null() { + let p: *const isize = null(); + assert!(p.is_null()); + + let q = p.wrapping_offset(1); + assert!(!q.is_null()); + + let mp: *mut isize = null_mut(); + assert!(mp.is_null()); + + let mq = mp.wrapping_offset(1); + assert!(!mq.is_null()); + + // Pointers to unsized types -- slices + let s: &mut [u8] = &mut [1, 2, 3]; + let cs: *const [u8] = s; + assert!(!cs.is_null()); + + let ms: *mut [u8] = s; + assert!(!ms.is_null()); + + let cz: *const [u8] = &[]; + assert!(!cz.is_null()); + + let mz: *mut [u8] = &mut []; + assert!(!mz.is_null()); + + let ncs: *const [u8] = null::<[u8; 3]>(); + assert!(ncs.is_null()); + + let nms: *mut [u8] = null_mut::<[u8; 3]>(); + assert!(nms.is_null()); + + // Pointers to unsized types -- trait objects + let ci: *const dyn ToString = &3; + assert!(!ci.is_null()); + + let mi: *mut dyn ToString = &mut 3; + assert!(!mi.is_null()); + + let nci: *const dyn ToString = null::(); + assert!(nci.is_null()); + + let nmi: *mut dyn ToString = null_mut::(); + assert!(nmi.is_null()); + + extern "C" { + type Extern; + } + let ec: *const Extern = null::(); + assert!(ec.is_null()); + + let em: *mut Extern = null_mut::(); + assert!(em.is_null()); +} + +#[test] +fn test_as_ref() { + unsafe { + let p: *const isize = null(); + assert_eq!(p.as_ref(), None); + + let q: *const isize = &2; + assert_eq!(q.as_ref().unwrap(), &2); + + let p: *mut isize = null_mut(); + assert_eq!(p.as_ref(), None); + + let q: *mut isize = &mut 2; + assert_eq!(q.as_ref().unwrap(), &2); + + // Lifetime inference + let u = 2isize; + { + let p = &u as *const isize; + assert_eq!(p.as_ref().unwrap(), &2); + } + + // Pointers to unsized types -- slices + let s: &mut [u8] = &mut [1, 2, 3]; + let cs: *const [u8] = s; + assert_eq!(cs.as_ref(), Some(&*s)); + + let ms: *mut [u8] = s; + assert_eq!(ms.as_ref(), Some(&*s)); + + let cz: *const [u8] = &[]; + assert_eq!(cz.as_ref(), Some(&[][..])); + + let mz: *mut [u8] = &mut []; + assert_eq!(mz.as_ref(), Some(&[][..])); + + let ncs: *const [u8] = null::<[u8; 3]>(); + assert_eq!(ncs.as_ref(), None); + + let nms: *mut [u8] = null_mut::<[u8; 3]>(); + assert_eq!(nms.as_ref(), None); + + // Pointers to unsized types -- trait objects + let ci: *const dyn ToString = &3; + assert!(ci.as_ref().is_some()); + + let mi: *mut dyn ToString = &mut 3; + assert!(mi.as_ref().is_some()); + + let nci: *const dyn ToString = null::(); + assert!(nci.as_ref().is_none()); + + let nmi: *mut dyn ToString = null_mut::(); + assert!(nmi.as_ref().is_none()); + } +} + +#[test] +fn test_as_mut() { + unsafe { + let p: *mut isize = null_mut(); + assert!(p.as_mut() == None); + + let q: *mut isize = &mut 2; + assert!(q.as_mut().unwrap() == &mut 2); + + // Lifetime inference + let mut u = 2isize; + { + let p = &mut u as *mut isize; + assert!(p.as_mut().unwrap() == &mut 2); + } + + // Pointers to unsized types -- slices + let s: &mut [u8] = &mut [1, 2, 3]; + let ms: *mut [u8] = s; + assert_eq!(ms.as_mut(), Some(&mut [1, 2, 3][..])); + + let mz: *mut [u8] = &mut []; + assert_eq!(mz.as_mut(), Some(&mut [][..])); + + let nms: *mut [u8] = null_mut::<[u8; 3]>(); + assert_eq!(nms.as_mut(), None); + + // Pointers to unsized types -- trait objects + let mi: *mut dyn ToString = &mut 3; + assert!(mi.as_mut().is_some()); + + let nmi: *mut dyn ToString = null_mut::(); + assert!(nmi.as_mut().is_none()); + } +} + +#[test] +fn test_ptr_addition() { + unsafe { + let xs = vec![5; 16]; + let mut ptr = xs.as_ptr(); + let end = ptr.offset(16); + + while ptr < end { + assert_eq!(*ptr, 5); + ptr = ptr.offset(1); + } + + let mut xs_mut = xs; + let mut m_ptr = xs_mut.as_mut_ptr(); + let m_end = m_ptr.offset(16); + + while m_ptr < m_end { + *m_ptr += 5; + m_ptr = m_ptr.offset(1); + } + + assert!(xs_mut == vec![10; 16]); + } +} + +#[test] +fn test_ptr_subtraction() { + unsafe { + let xs = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let mut idx = 9; + let ptr = xs.as_ptr(); + + while idx >= 0 { + assert_eq!(*(ptr.offset(idx as isize)), idx as isize); + idx = idx - 1; + } + + let mut xs_mut = xs; + let m_start = xs_mut.as_mut_ptr(); + let mut m_ptr = m_start.offset(9); + + loop { + *m_ptr += *m_ptr; + if m_ptr == m_start { + break; + } + m_ptr = m_ptr.offset(-1); + } + + assert_eq!(xs_mut, [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]); + } +} + +#[test] +fn test_set_memory() { + let mut xs = [0u8; 20]; + let ptr = xs.as_mut_ptr(); + unsafe { + write_bytes(ptr, 5u8, xs.len()); + } + assert!(xs == [5u8; 20]); +} + +#[test] +fn test_set_memory_const() { + const XS: [u8; 20] = { + let mut xs = [0u8; 20]; + let ptr = xs.as_mut_ptr(); + unsafe { + ptr.write_bytes(5u8, xs.len()); + } + xs + }; + + assert!(XS == [5u8; 20]); +} + +#[test] +fn test_unsized_nonnull() { + let xs: &[i32] = &[1, 2, 3]; + let ptr = unsafe { NonNull::new_unchecked(xs as *const [i32] as *mut [i32]) }; + let ys = unsafe { ptr.as_ref() }; + let zs: &[i32] = &[1, 2, 3]; + assert!(ys == zs); +} + +#[test] +fn test_const_nonnull_new() { + const { + assert!(NonNull::new(core::ptr::null_mut::<()>()).is_none()); + + let value = &mut 0u32; + let mut ptr = NonNull::new(value).unwrap(); + unsafe { *ptr.as_mut() = 42 }; + + let reference = unsafe { &*ptr.as_ref() }; + assert!(*reference == *value); + assert!(*reference == 42); + }; +} + +#[test] +#[cfg(unix)] // printf may not be available on other platforms +#[allow(deprecated)] // For SipHasher +#[allow(unpredictable_function_pointer_comparisons)] +pub fn test_variadic_fnptr() { + use core::ffi; + use core::hash::{Hash, SipHasher}; + extern "C" { + // This needs to use the correct function signature even though it isn't called as some + // codegen backends make it UB to declare a function with multiple conflicting signatures + // (like LLVM) while others straight up return an error (like Cranelift). + fn printf(_: *const ffi::c_char, ...) -> ffi::c_int; + } + let p: unsafe extern "C" fn(*const ffi::c_char, ...) -> ffi::c_int = printf; + let q = p.clone(); + assert_eq!(p, q); + assert!(!(p < q)); + let mut s = SipHasher::new(); + assert_eq!(p.hash(&mut s), q.hash(&mut s)); +} + +#[test] +fn write_unaligned_drop() { + thread_local! { + static DROPS: RefCell> = RefCell::new(Vec::new()); + } + + struct Dropper(u32); + + impl Drop for Dropper { + fn drop(&mut self) { + DROPS.with(|d| d.borrow_mut().push(self.0)); + } + } + + { + let c = Dropper(0); + let mut t = Dropper(1); + unsafe { + write_unaligned(&mut t, c); + } + } + DROPS.with(|d| assert_eq!(*d.borrow(), [0])); +} + +#[test] +fn align_offset_zst() { + // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at + // all, because no amount of elements will align the pointer. + let mut p = 1; + while p < 1024 { + assert_eq!(ptr::without_provenance::<()>(p).align_offset(p), 0); + if p != 1 { + assert_eq!(ptr::without_provenance::<()>(p + 1).align_offset(p), !0); + } + p = (p + 1).next_power_of_two(); + } +} + +#[test] +fn align_offset_stride_one() { + // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to + // number of bytes. + let mut align = 1; + while align < 1024 { + for ptr in 1..2 * align { + let expected = ptr % align; + let offset = if expected == 0 { 0 } else { align - expected }; + assert_eq!( + ptr::without_provenance::(ptr).align_offset(align), + offset, + "ptr = {}, align = {}, size = 1", + ptr, + align + ); + } + align = (align + 1).next_power_of_two(); + } +} + +#[test] +fn align_offset_various_strides() { + unsafe fn test_stride(ptr: *const T, align: usize) -> bool { + let numptr = ptr as usize; + let mut expected = usize::MAX; + // Naive but definitely correct way to find the *first* aligned element of stride::. + for el in 0..align { + if (numptr + el * ::std::mem::size_of::()) % align == 0 { + expected = el; + break; + } + } + let got = ptr.align_offset(align); + if got != expected { + eprintln!( + "aligning {:p} (with stride of {}) to {}, expected {}, got {}", + ptr, + ::std::mem::size_of::(), + align, + expected, + got + ); + return true; + } + return false; + } + + // For pointers of stride != 1, we verify the algorithm against the naivest possible + // implementation + let mut align = 1; + let mut x = false; + // Miri is too slow + let limit = if cfg!(miri) { 32 } else { 1024 }; + while align < limit { + for ptr in 1usize..4 * align { + unsafe { + #[repr(packed)] + struct A3(#[allow(dead_code)] u16, #[allow(dead_code)] u8); + x |= test_stride::(ptr::without_provenance::(ptr), align); + + struct A4(#[allow(dead_code)] u32); + x |= test_stride::(ptr::without_provenance::(ptr), align); + + #[repr(packed)] + struct A5(#[allow(dead_code)] u32, #[allow(dead_code)] u8); + x |= test_stride::(ptr::without_provenance::(ptr), align); + + #[repr(packed)] + struct A6(#[allow(dead_code)] u32, #[allow(dead_code)] u16); + x |= test_stride::(ptr::without_provenance::(ptr), align); + + #[repr(packed)] + struct A7(#[allow(dead_code)] u32, #[allow(dead_code)] u16, #[allow(dead_code)] u8); + x |= test_stride::(ptr::without_provenance::(ptr), align); + + #[repr(packed)] + struct A8(#[allow(dead_code)] u32, #[allow(dead_code)] u32); + x |= test_stride::(ptr::without_provenance::(ptr), align); + + #[repr(packed)] + struct A9(#[allow(dead_code)] u32, #[allow(dead_code)] u32, #[allow(dead_code)] u8); + x |= test_stride::(ptr::without_provenance::(ptr), align); + + #[repr(packed)] + struct A10( + #[allow(dead_code)] u32, + #[allow(dead_code)] u32, + #[allow(dead_code)] u16, + ); + x |= test_stride::(ptr::without_provenance::(ptr), align); + + x |= test_stride::(ptr::without_provenance::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); + } + } + align = (align + 1).next_power_of_two(); + } + assert!(!x); +} + +#[test] +fn align_offset_issue_103361() { + #[cfg(target_pointer_width = "64")] + const SIZE: usize = 1 << 47; + #[cfg(target_pointer_width = "32")] + const SIZE: usize = 1 << 30; + #[cfg(target_pointer_width = "16")] + const SIZE: usize = 1 << 13; + struct HugeSize(#[allow(dead_code)] [u8; SIZE - 1]); + let _ = ptr::without_provenance::(SIZE).align_offset(SIZE); +} + +#[test] +fn is_aligned() { + let data = 42; + let ptr: *const i32 = &data; + assert!(ptr.is_aligned()); + assert!(ptr.is_aligned_to(1)); + assert!(ptr.is_aligned_to(2)); + assert!(ptr.is_aligned_to(4)); + assert!(ptr.wrapping_byte_add(2).is_aligned_to(1)); + assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); + assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); + + // At runtime either `ptr` or `ptr+1` is aligned to 8. + assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); +} + +#[test] +fn offset_from() { + let mut a = [0; 5]; + let ptr1: *mut i32 = &mut a[1]; + let ptr2: *mut i32 = &mut a[3]; + unsafe { + assert_eq!(ptr2.offset_from(ptr1), 2); + assert_eq!(ptr1.offset_from(ptr2), -2); + assert_eq!(ptr1.offset(2), ptr2); + assert_eq!(ptr2.offset(-2), ptr1); + } +} + +#[test] +fn ptr_metadata() { + struct Unit; + struct Pair(A, B); + extern "C" { + type Extern; + } + let () = metadata(&()); + let () = metadata(&Unit); + let () = metadata(&4_u32); + let () = metadata(&String::new()); + let () = metadata(&Some(4_u32)); + let () = metadata(&ptr_metadata); + let () = metadata(&|| {}); + let () = metadata(&[4, 7]); + let () = metadata(&(4, String::new())); + let () = metadata(&Pair(4, String::new())); + let () = metadata(ptr::null::<()>() as *const Extern); + let () = metadata(ptr::null::<()>() as *const <&u32 as std::ops::Deref>::Target); + + assert_eq!(metadata("foo"), 3_usize); + assert_eq!(metadata(&[4, 7][..]), 2_usize); + + let dst_tuple: &(bool, [u8]) = &(true, [0x66, 0x6F, 0x6F]); + let dst_struct: &Pair = &Pair(true, [0x66, 0x6F, 0x6F]); + assert_eq!(metadata(dst_tuple), 3_usize); + assert_eq!(metadata(dst_struct), 3_usize); + unsafe { + let dst_tuple: &(bool, str) = std::mem::transmute(dst_tuple); + let dst_struct: &Pair = std::mem::transmute(dst_struct); + assert_eq!(&dst_tuple.1, "foo"); + assert_eq!(&dst_struct.1, "foo"); + assert_eq!(metadata(dst_tuple), 3_usize); + assert_eq!(metadata(dst_struct), 3_usize); + } + + let vtable_1: DynMetadata = metadata(&4_u16 as &dyn Debug); + let vtable_2: DynMetadata = metadata(&4_u16 as &dyn Display); + let vtable_3: DynMetadata = metadata(&4_u32 as &dyn Display); + let vtable_4: DynMetadata = metadata(&(true, 7_u32) as &(bool, dyn Display)); + let vtable_5: DynMetadata = + metadata(&Pair(true, 7_u32) as &Pair); + unsafe { + let address_1: *const () = std::mem::transmute(vtable_1); + let address_2: *const () = std::mem::transmute(vtable_2); + let address_3: *const () = std::mem::transmute(vtable_3); + let address_4: *const () = std::mem::transmute(vtable_4); + let address_5: *const () = std::mem::transmute(vtable_5); + // Different trait => different vtable pointer + assert_ne!(address_1, address_2); + // Different erased type => different vtable pointer + assert_ne!(address_2, address_3); + // Same erased type and same trait => same vtable pointer. + // This is *not guaranteed*, so we skip it in Miri. + if !cfg!(miri) { + assert_eq!(address_3, address_4); + assert_eq!(address_3, address_5); + } + } +} + +#[test] +fn ptr_metadata_bounds() { + fn metadata_eq_method_address() -> usize { + // The `Metadata` associated type has an `Ord` bound, so this is valid: + <::Metadata as PartialEq>::eq as usize + } + // "Synthetic" trait impls generated by the compiler like those of `Pointee` + // are not checked for bounds of associated type. + // So with a buggy core we could have both: + // * `::Metadata == DynMetadata` + // * `DynMetadata: !PartialEq` + // … and cause an ICE here: + metadata_eq_method_address::(); + + // For this reason, let’s check here that bounds are satisfied: + + let _ = static_assert_expected_bounds_for_metadata::<()>; + let _ = static_assert_expected_bounds_for_metadata::; + let _ = static_assert_expected_bounds_for_metadata::>; + fn _static_assert_associated_type() { + let _ = static_assert_expected_bounds_for_metadata::<::Metadata>; + } + + fn static_assert_expected_bounds_for_metadata() + where + // Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs` + Meta: Debug + Copy + Send + Sync + Ord + std::hash::Hash + Unpin + Freeze, + { + } +} + +#[test] +fn pointee_metadata_debug() { + assert_eq!("()", format!("{:?}", metadata::(&17))); + assert_eq!("2", format!("{:?}", metadata::<[u32]>(&[19, 23]))); + let for_dyn = format!("{:?}", metadata::(&29)); + assert!(for_dyn.starts_with("DynMetadata(0x"), "{:?}", for_dyn); +} + +#[test] +fn dyn_metadata() { + #[derive(Debug)] + #[repr(align(32))] + struct Something(#[allow(dead_code)] [u8; 47]); + + let value = Something([0; 47]); + let trait_object: &dyn Debug = &value; + let meta = metadata(trait_object); + + assert_eq!(meta.size_of(), 64); + assert_eq!(meta.size_of(), std::mem::size_of::()); + assert_eq!(meta.align_of(), 32); + assert_eq!(meta.align_of(), std::mem::align_of::()); + assert_eq!(meta.layout(), std::alloc::Layout::new::()); + + assert!(format!("{meta:?}").starts_with("DynMetadata(0x")); +} + +#[test] +fn from_raw_parts() { + let mut value = 5_u32; + let address = &mut value as *mut _ as *mut (); + let trait_object: &dyn Display = &mut value; + let vtable = metadata(trait_object); + let trait_object = NonNull::from(trait_object); + + assert_eq!(ptr::from_raw_parts(address, vtable), trait_object.as_ptr()); + assert_eq!(ptr::from_raw_parts_mut(address, vtable), trait_object.as_ptr()); + assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), vtable), trait_object); + + let mut array = [5_u32, 5, 5, 5, 5]; + let address = &mut array as *mut _ as *mut (); + let array_ptr = NonNull::from(&mut array); + let slice_ptr = NonNull::from(&mut array[..]); + + assert_eq!(ptr::from_raw_parts(address, ()), array_ptr.as_ptr()); + assert_eq!(ptr::from_raw_parts_mut(address, ()), array_ptr.as_ptr()); + assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), ()), array_ptr); + + assert_eq!(ptr::from_raw_parts(address, 5), slice_ptr.as_ptr()); + assert_eq!(ptr::from_raw_parts_mut(address, 5), slice_ptr.as_ptr()); + assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), 5), slice_ptr); +} + +#[test] +fn thin_box() { + let foo = ThinBox::::new(4); + assert_eq!(foo.to_string(), "4"); + drop(foo); + let bar = ThinBox::::new(7); + assert_eq!(bar.to_string(), "7"); + + // A slightly more interesting library that could be built on top of metadata APIs. + // + // * It could be generalized to any `T: ?Sized` (not just trait object) + // if `{size,align}_of_for_meta(T::Metadata)` are added. + // * Constructing a `ThinBox` without consuming and deallocating a `Box` + // requires either the unstable `Unsize` marker trait, + // or the unstable `unsized_locals` language feature, + // or taking `&dyn T` and restricting to `T: Copy`. + + use std::alloc::*; + use std::marker::PhantomData; + + struct ThinBox + where + T: ?Sized + Pointee>, + { + ptr: NonNull>, + phantom: PhantomData, + } + + impl ThinBox + where + T: ?Sized + Pointee>, + { + pub fn new>(value: Value) -> Self { + let unsized_: &T = &value; + let meta = metadata(unsized_); + let meta_layout = Layout::for_value(&meta); + let value_layout = Layout::for_value(&value); + let (layout, offset) = meta_layout.extend(value_layout).unwrap(); + // `DynMetadata` is pointer-sized: + assert!(layout.size() > 0); + // If `ThinBox` is generalized to any `T: ?Sized`, + // handle ZSTs with a dangling pointer without going through `alloc()`, + // like `Box` does. + unsafe { + let ptr = NonNull::new(alloc(layout)) + .unwrap_or_else(|| handle_alloc_error(layout)) + .cast::>(); + ptr.as_ptr().write(meta); + ptr.as_ptr().byte_add(offset).cast::().write(value); + Self { ptr, phantom: PhantomData } + } + } + + fn meta(&self) -> DynMetadata { + unsafe { *self.ptr.as_ref() } + } + + fn layout(&self) -> (Layout, usize) { + let meta = self.meta(); + Layout::for_value(&meta).extend(meta.layout()).unwrap() + } + + fn value_ptr(&self) -> *const T { + let (_, offset) = self.layout(); + let data_ptr = unsafe { self.ptr.cast::().as_ptr().add(offset) }; + ptr::from_raw_parts(data_ptr, self.meta()) + } + + fn value_mut_ptr(&mut self) -> *mut T { + let (_, offset) = self.layout(); + // FIXME: can this line be shared with the same in `value_ptr()` + // without upsetting Stacked Borrows? + let data_ptr = unsafe { self.ptr.cast::().as_ptr().add(offset) }; + from_raw_parts_mut(data_ptr, self.meta()) + } + } + + impl std::ops::Deref for ThinBox + where + T: ?Sized + Pointee>, + { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.value_ptr() } + } + } + + impl std::ops::DerefMut for ThinBox + where + T: ?Sized + Pointee>, + { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.value_mut_ptr() } + } + } + + impl std::ops::Drop for ThinBox + where + T: ?Sized + Pointee>, + { + fn drop(&mut self) { + let (layout, _) = self.layout(); + unsafe { + drop_in_place::(&mut **self); + dealloc(self.ptr.cast().as_ptr(), layout); + } + } + } +} + +#[test] +fn nonnull_tagged_pointer_with_provenance() { + let raw_pointer = Box::into_raw(Box::new(10)); + + let mut p = TaggedPointer::new(raw_pointer).unwrap(); + assert_eq!(p.tag(), 0); + + p.set_tag(1); + assert_eq!(p.tag(), 1); + assert_eq!(unsafe { *p.pointer().as_ptr() }, 10); + + p.set_tag(3); + assert_eq!(p.tag(), 3); + assert_eq!(unsafe { *p.pointer().as_ptr() }, 10); + + unsafe { drop(Box::from_raw(p.pointer().as_ptr())) }; + + /// A non-null pointer type which carries several bits of metadata and maintains provenance. + #[repr(transparent)] + pub struct TaggedPointer(NonNull); + + impl Clone for TaggedPointer { + fn clone(&self) -> Self { + Self(self.0) + } + } + + impl Copy for TaggedPointer {} + + impl TaggedPointer { + /// The ABI-required minimum alignment of the `P` type. + pub const ALIGNMENT: usize = core::mem::align_of::(); + /// A mask for data-carrying bits of the address. + pub const DATA_MASK: usize = !Self::ADDRESS_MASK; + /// Number of available bits of storage in the address. + pub const NUM_BITS: u32 = Self::ALIGNMENT.trailing_zeros(); + /// A mask for the non-data-carrying bits of the address. + pub const ADDRESS_MASK: usize = usize::MAX << Self::NUM_BITS; + + /// Creates a new tagged pointer from a possibly null pointer. + pub fn new(pointer: *mut T) -> Option> { + Some(TaggedPointer(NonNull::new(pointer)?)) + } + + /// Consume this tagged pointer and produce a raw mutable pointer to the + /// memory location. + pub fn pointer(self) -> NonNull { + // SAFETY: The `addr` guaranteed to have bits set in the Self::ADDRESS_MASK, so the result will be non-null. + self.0 + .map_addr(|addr| unsafe { NonZero::new_unchecked(addr.get() & Self::ADDRESS_MASK) }) + } + + /// Consume this tagged pointer and produce the data it carries. + pub fn tag(&self) -> usize { + self.0.addr().get() & Self::DATA_MASK + } + + /// Update the data this tagged pointer carries to a new value. + pub fn set_tag(&mut self, data: usize) { + assert_eq!( + data & Self::ADDRESS_MASK, + 0, + "cannot set more data beyond the lowest NUM_BITS" + ); + let data = data & Self::DATA_MASK; + + // SAFETY: This value will always be non-zero because the upper bits (from + // ADDRESS_MASK) will always be non-zero. This a property of the type and its + // construction. + self.0 = self.0.map_addr(|addr| unsafe { + NonZero::new_unchecked((addr.get() & Self::ADDRESS_MASK) | data) + }) + } + } +} + +#[test] +fn swap_copy_untyped() { + // We call `{swap,copy}{,_nonoverlapping}` at `bool` type on data that is not a valid bool. + // These should all do untyped copies, so this should work fine. + let mut x = 5u8; + let mut y = 6u8; + + let ptr1 = addr_of_mut!(x).cast::(); + let ptr2 = addr_of_mut!(y).cast::(); + + unsafe { + ptr::swap(ptr1, ptr2); + ptr::swap_nonoverlapping(ptr1, ptr2, 1); + } + assert_eq!(x, 5); + assert_eq!(y, 6); + + unsafe { + ptr::copy(ptr1, ptr2, 1); + ptr::copy_nonoverlapping(ptr1, ptr2, 1); + } + assert_eq!(x, 5); + assert_eq!(y, 5); +} + +#[test] +fn test_const_copy_ptr() { + // `copy` and `copy_nonoverlapping` are thin layers on top of intrinsics. Ensure they correctly + // deal with pointers even when the pointers cross the boundary from one "element" being copied + // to another. + const { + let ptr1 = &1; + let mut ptr2 = &666; + + // Copy ptr1 to ptr2, bytewise. + unsafe { + ptr::copy( + &ptr1 as *const _ as *const MaybeUninit, + &mut ptr2 as *mut _ as *mut MaybeUninit, + mem::size_of::<&i32>(), + ); + } + + // Make sure they still work. + assert!(*ptr1 == 1); + assert!(*ptr2 == 1); + }; + + const { + let ptr1 = &1; + let mut ptr2 = &666; + + // Copy ptr1 to ptr2, bytewise. + unsafe { + ptr::copy_nonoverlapping( + &ptr1 as *const _ as *const MaybeUninit, + &mut ptr2 as *mut _ as *mut MaybeUninit, + mem::size_of::<&i32>(), + ); + } + + // Make sure they still work. + assert!(*ptr1 == 1); + assert!(*ptr2 == 1); + }; +} + +#[test] +fn test_const_swap_ptr() { + // The `swap` functions are implemented in the library, they are not primitives. + // Only `swap_nonoverlapping` takes a count; pointers that cross multiple elements + // are *not* supported. + // We put the pointer at an odd offset in the type and copy them as an array of bytes, + // which should catch most of the ways that the library implementation can get it wrong. + + #[cfg(target_pointer_width = "32")] + type HalfPtr = i16; + #[cfg(target_pointer_width = "64")] + type HalfPtr = i32; + + #[repr(C, packed)] + #[allow(unused)] + struct S { + f1: HalfPtr, + // Crucially this field is at an offset that is not a multiple of the pointer size. + ptr: &'static i32, + // Make sure the entire type does not have a power-of-2 size: + // make it 3 pointers in size. This used to hit a bug in `swap_nonoverlapping`. + f2: [HalfPtr; 3], + } + + // Ensure the entire thing is usize-aligned, so in principle this + // looks like it could be eligible for a `usize` copying loop. + #[cfg_attr(target_pointer_width = "32", repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", repr(align(8)))] + struct A(S); + + const { + let mut s1 = A(S { ptr: &1, f1: 0, f2: [0; 3] }); + let mut s2 = A(S { ptr: &666, f1: 0, f2: [0; 3] }); + + // Swap ptr1 and ptr2, as an array. + type T = [u8; mem::size_of::()]; + unsafe { + ptr::swap(ptr::from_mut(&mut s1).cast::(), ptr::from_mut(&mut s2).cast::()); + } + + // Make sure they still work. + assert!(*s1.0.ptr == 666); + assert!(*s2.0.ptr == 1); + + // Swap them back, again as an array. + unsafe { + ptr::swap_nonoverlapping( + ptr::from_mut(&mut s1).cast::(), + ptr::from_mut(&mut s2).cast::(), + 1, + ); + } + + // Make sure they still work. + assert!(*s1.0.ptr == 1); + assert!(*s2.0.ptr == 666); + }; +} + +#[test] +fn test_null_array_as_slice() { + let arr: *mut [u8; 4] = null_mut(); + let ptr: *mut [u8] = arr.as_mut_slice(); + assert!(ptr.is_null()); + assert_eq!(ptr.len(), 4); + + let arr: *const [u8; 4] = null(); + let ptr: *const [u8] = arr.as_slice(); + assert!(ptr.is_null()); + assert_eq!(ptr.len(), 4); +} + +#[test] +fn test_ptr_from_raw_parts_in_const() { + const EMPTY_SLICE_PTR: *const [i32] = + std::ptr::slice_from_raw_parts(std::ptr::without_provenance(123), 456); + assert_eq!(EMPTY_SLICE_PTR.addr(), 123); + assert_eq!(EMPTY_SLICE_PTR.len(), 456); +} + +#[test] +fn test_ptr_metadata_in_const() { + use std::fmt::Debug; + + const ARRAY_META: () = std::ptr::metadata::<[u16; 3]>(&[1, 2, 3]); + const SLICE_META: usize = std::ptr::metadata::<[u16]>(&[1, 2, 3]); + const DYN_META: DynMetadata = std::ptr::metadata::(&[0_u8; 42]); + assert_eq!(ARRAY_META, ()); + assert_eq!(SLICE_META, 3); + assert_eq!(DYN_META.size_of(), 42); +} diff --git a/library/coretests/tests/result.rs b/library/coretests/tests/result.rs new file mode 100644 index 00000000000..90ec844bc57 --- /dev/null +++ b/library/coretests/tests/result.rs @@ -0,0 +1,423 @@ +use core::ops::DerefMut; +use core::option::*; + +fn op1() -> Result { + Ok(666) +} +fn op2() -> Result { + Err("sadface") +} + +#[test] +fn test_and() { + assert_eq!(op1().and(Ok(667)).unwrap(), 667); + assert_eq!(op1().and(Err::("bad")).unwrap_err(), "bad"); + + assert_eq!(op2().and(Ok(667)).unwrap_err(), "sadface"); + assert_eq!(op2().and(Err::("bad")).unwrap_err(), "sadface"); +} + +#[test] +fn test_and_then() { + assert_eq!(op1().and_then(|i| Ok::(i + 1)).unwrap(), 667); + assert_eq!(op1().and_then(|_| Err::("bad")).unwrap_err(), "bad"); + + assert_eq!(op2().and_then(|i| Ok::(i + 1)).unwrap_err(), "sadface"); + assert_eq!(op2().and_then(|_| Err::("bad")).unwrap_err(), "sadface"); +} + +#[test] +fn test_or() { + assert_eq!(op1().or(Ok::<_, &'static str>(667)).unwrap(), 666); + assert_eq!(op1().or(Err("bad")).unwrap(), 666); + + assert_eq!(op2().or(Ok::<_, &'static str>(667)).unwrap(), 667); + assert_eq!(op2().or(Err("bad")).unwrap_err(), "bad"); +} + +#[test] +fn test_or_else() { + assert_eq!(op1().or_else(|_| Ok::(667)).unwrap(), 666); + assert_eq!(op1().or_else(|e| Err::(e)).unwrap(), 666); + + assert_eq!(op2().or_else(|_| Ok::(667)).unwrap(), 667); + assert_eq!(op2().or_else(|e| Err::(e)).unwrap_err(), "sadface"); +} + +#[test] +fn test_impl_map() { + assert!(Ok::(1).map(|x| x + 1) == Ok(2)); + assert!(Err::(1).map(|x| x + 1) == Err(1)); +} + +#[test] +fn test_impl_map_err() { + assert!(Ok::(1).map_err(|x| x + 1) == Ok(1)); + assert!(Err::(1).map_err(|x| x + 1) == Err(2)); +} + +#[test] +fn test_collect() { + let v: Result, ()> = (0..0).map(|_| Ok::(0)).collect(); + assert!(v == Ok(vec![])); + + let v: Result, ()> = (0..3).map(|x| Ok::(x)).collect(); + assert!(v == Ok(vec![0, 1, 2])); + + let v: Result, isize> = (0..3).map(|x| if x > 1 { Err(x) } else { Ok(x) }).collect(); + assert!(v == Err(2)); + + // test that it does not take more elements than it needs + let mut functions: [Box Result<(), isize>>; 3] = + [Box::new(|| Ok(())), Box::new(|| Err(1)), Box::new(|| panic!())]; + + let v: Result, isize> = functions.iter_mut().map(|f| (*f)()).collect(); + assert!(v == Err(1)); +} + +#[test] +fn test_fmt_default() { + let ok: Result = Ok(100); + let err: Result = Err("Err"); + + let s = format!("{ok:?}"); + assert_eq!(s, "Ok(100)"); + let s = format!("{err:?}"); + assert_eq!(s, "Err(\"Err\")"); +} + +#[test] +fn test_unwrap_or() { + let ok: Result = Ok(100); + let ok_err: Result = Err("Err"); + + assert_eq!(ok.unwrap_or(50), 100); + assert_eq!(ok_err.unwrap_or(50), 50); +} + +#[test] +fn test_unwrap_or_else() { + fn handler(msg: &'static str) -> isize { + if msg == "I got this." { 50 } else { panic!("BadBad") } + } + + let ok: Result = Ok(100); + let ok_err: Result = Err("I got this."); + + assert_eq!(ok.unwrap_or_else(handler), 100); + assert_eq!(ok_err.unwrap_or_else(handler), 50); +} + +#[test] +#[should_panic] +pub fn test_unwrap_or_else_panic() { + fn handler(msg: &'static str) -> isize { + if msg == "I got this." { 50 } else { panic!("BadBad") } + } + + let bad_err: Result = Err("Unrecoverable mess."); + let _: isize = bad_err.unwrap_or_else(handler); +} + +#[test] +fn test_unwrap_unchecked() { + let ok: Result = Ok(100); + assert_eq!(unsafe { ok.unwrap_unchecked() }, 100); +} + +#[test] +fn test_unwrap_err_unchecked() { + let ok_err: Result = Err("Err"); + assert_eq!(unsafe { ok_err.unwrap_err_unchecked() }, "Err"); +} + +#[test] +pub fn test_expect_ok() { + let ok: Result = Ok(100); + assert_eq!(ok.expect("Unexpected error"), 100); +} +#[test] +#[should_panic(expected = "Got expected error: \"All good\"")] +pub fn test_expect_err() { + let err: Result = Err("All good"); + err.expect("Got expected error"); +} + +#[test] +pub fn test_expect_err_err() { + let ok: Result<&'static str, isize> = Err(100); + assert_eq!(ok.expect_err("Unexpected ok"), 100); +} +#[test] +#[should_panic(expected = "Got expected ok: \"All good\"")] +pub fn test_expect_err_ok() { + let err: Result<&'static str, isize> = Ok("All good"); + err.expect_err("Got expected ok"); +} + +#[test] +pub fn test_iter() { + let ok: Result = Ok(100); + let mut it = ok.iter(); + assert_eq!(it.size_hint(), (1, Some(1))); + assert_eq!(it.next(), Some(&100)); + assert_eq!(it.size_hint(), (0, Some(0))); + assert!(it.next().is_none()); + assert_eq!((&ok).into_iter().next(), Some(&100)); + + let err: Result = Err("error"); + assert_eq!(err.iter().next(), None); +} + +#[test] +#[allow(for_loops_over_fallibles)] +pub fn test_iter_mut() { + let mut ok: Result = Ok(100); + for loc in ok.iter_mut() { + *loc = 200; + } + assert_eq!(ok, Ok(200)); + for loc in &mut ok { + *loc = 300; + } + assert_eq!(ok, Ok(300)); + + let mut err: Result = Err("error"); + for loc in err.iter_mut() { + *loc = 200; + } + assert_eq!(err, Err("error")); +} + +#[test] +pub fn test_unwrap_or_default() { + assert_eq!(op1().unwrap_or_default(), 666); + assert_eq!(op2().unwrap_or_default(), 0); +} + +#[test] +#[allow(non_local_definitions)] +pub fn test_into_ok() { + fn infallible_op() -> Result { + Ok(666) + } + + assert_eq!(infallible_op().into_ok(), 666); + + enum MyNeverToken {} + impl From for ! { + fn from(never: MyNeverToken) -> ! { + match never {} + } + } + + fn infallible_op2() -> Result { + Ok(667) + } + + assert_eq!(infallible_op2().into_ok(), 667); +} + +#[test] +#[allow(non_local_definitions)] +pub fn test_into_err() { + fn until_error_op() -> Result { + Err(666) + } + + assert_eq!(until_error_op().into_err(), 666); + + enum MyNeverToken {} + impl From for ! { + fn from(never: MyNeverToken) -> ! { + match never {} + } + } + + fn until_error_op2() -> Result { + Err(667) + } + + assert_eq!(until_error_op2().into_err(), 667); +} + +#[test] +fn test_try() { + fn try_result_ok() -> Result { + let result: Result = Ok(1); + let val = result?; + Ok(val) + } + assert_eq!(try_result_ok(), Ok(1)); + + fn try_result_err() -> Result { + let result: Result = Err(1); + let val = result?; + Ok(val) + } + assert_eq!(try_result_err(), Err(1)); +} + +#[test] +fn test_result_as_deref() { + // &Result::Ok(T).as_deref() -> + // Result<&T::Deref::Target, &E>::Ok(&*T) + let ref_ok = &Result::Ok::<&i32, u8>(&42); + let expected_result = Result::Ok::<&i32, &u8>(&42); + assert_eq!(ref_ok.as_deref(), expected_result); + + let ref_ok = &Result::Ok::(String::from("a result")); + let expected_result = Result::Ok::<&str, &u32>("a result"); + assert_eq!(ref_ok.as_deref(), expected_result); + + let ref_ok = &Result::Ok::, u32>(vec![1, 2, 3, 4, 5]); + let expected_result = Result::Ok::<&[i32], &u32>([1, 2, 3, 4, 5].as_slice()); + assert_eq!(ref_ok.as_deref(), expected_result); + + // &Result::Err(T).as_deref() -> + // Result<&T::Deref::Target, &E>::Err(&*E) + let val = 41; + let ref_err = &Result::Err::<&u8, i32>(val); + let expected_result = Result::Err::<&u8, &i32>(&val); + assert_eq!(ref_err.as_deref(), expected_result); + + let s = String::from("an error"); + let ref_err = &Result::Err::<&u32, String>(s.clone()); + let expected_result = Result::Err::<&u32, &String>(&s); + assert_eq!(ref_err.as_deref(), expected_result); + + let v = vec![5, 4, 3, 2, 1]; + let ref_err = &Result::Err::<&u32, Vec>(v.clone()); + let expected_result = Result::Err::<&u32, &Vec>(&v); + assert_eq!(ref_err.as_deref(), expected_result); +} + +#[test] +fn test_result_as_deref_mut() { + // &mut Result::Ok(T).as_deref_mut() -> + // Result<&mut T::DerefMut::Target, &mut E>::Ok(&mut *T) + let mut val = 42; + let mut expected_val = 42; + let mut_ok = &mut Result::Ok::<&mut i32, u8>(&mut val); + let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val); + assert_eq!(mut_ok.as_deref_mut(), expected_result); + + let mut expected_string = String::from("a result"); + let mut_ok = &mut Result::Ok::(expected_string.clone()); + let expected_result = Result::Ok::<&mut str, &mut u32>(expected_string.deref_mut()); + assert_eq!(mut_ok.as_deref_mut(), expected_result); + + let mut expected_vec = vec![1, 2, 3, 4, 5]; + let mut_ok = &mut Result::Ok::, u32>(expected_vec.clone()); + let expected_result = Result::Ok::<&mut [i32], &mut u32>(expected_vec.as_mut_slice()); + assert_eq!(mut_ok.as_deref_mut(), expected_result); + + // &mut Result::Err(T).as_deref_mut() -> + // Result<&mut T, &mut E>::Err(&mut *E) + let mut val = 41; + let mut_err = &mut Result::Err::<&mut u8, i32>(val); + let expected_result = Result::Err::<&mut u8, &mut i32>(&mut val); + assert_eq!(mut_err.as_deref_mut(), expected_result); + + let mut expected_string = String::from("an error"); + let mut_err = &mut Result::Err::<&mut u32, String>(expected_string.clone()); + let expected_result = Result::Err::<&mut u32, &mut String>(&mut expected_string); + assert_eq!(mut_err.as_deref_mut(), expected_result); + + let mut expected_vec = vec![5, 4, 3, 2, 1]; + let mut_err = &mut Result::Err::<&mut u32, Vec>(expected_vec.clone()); + let expected_result = Result::Err::<&mut u32, &mut Vec>(&mut expected_vec); + assert_eq!(mut_err.as_deref_mut(), expected_result); +} + +#[test] +fn result_const() { + // test that the methods of `Result` are usable in a const context + + const RESULT: Result = Ok(32); + + const REF: Result<&usize, &bool> = RESULT.as_ref(); + assert_eq!(REF, Ok(&32)); + + const IS_OK: bool = RESULT.is_ok(); + assert!(IS_OK); + + const IS_ERR: bool = RESULT.is_err(); + assert!(!IS_ERR) +} + +#[test] +const fn result_const_mut() { + let mut result: Result = Ok(32); + + { + let as_mut = result.as_mut(); + match as_mut { + Ok(v) => *v = 42, + Err(_) => unreachable!(), + } + } + + let mut result_err: Result = Err(false); + + { + let as_mut = result_err.as_mut(); + match as_mut { + Ok(_) => unreachable!(), + Err(v) => *v = true, + } + } +} + +#[test] +fn result_opt_conversions() { + #[derive(Copy, Clone, Debug, PartialEq)] + struct BadNumErr; + + fn try_num(x: i32) -> Result { + if x <= 5 { Ok(x + 1) } else { Err(BadNumErr) } + } + + type ResOpt = Result, BadNumErr>; + type OptRes = Option>; + + let mut x: ResOpt = Ok(Some(5)); + let mut y: OptRes = Some(Ok(5)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Ok(None); + y = None; + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Err(BadNumErr); + y = Some(Err(BadNumErr)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + let res: Result, BadNumErr> = (0..10) + .map(|x| { + let y = try_num(x)?; + Ok(if y % 2 == 0 { Some(y - 1) } else { None }) + }) + .filter_map(Result::transpose) + .collect(); + + assert_eq!(res, Err(BadNumErr)) +} + +#[test] +fn result_try_trait_v2_branch() { + use core::num::NonZero; + use core::ops::ControlFlow::*; + use core::ops::Try; + + assert_eq!(Ok::(4).branch(), Continue(4)); + assert_eq!(Err::(4).branch(), Break(Err(4))); + let one = NonZero::new(1).unwrap(); + assert_eq!(Ok::<(), NonZero>(()).branch(), Continue(())); + assert_eq!(Err::<(), NonZero>(one).branch(), Break(Err(one))); + assert_eq!(Ok::, ()>(one).branch(), Continue(one)); + assert_eq!(Err::, ()>(()).branch(), Break(Err(()))); +} diff --git a/library/coretests/tests/simd.rs b/library/coretests/tests/simd.rs new file mode 100644 index 00000000000..b8b5f26ca3f --- /dev/null +++ b/library/coretests/tests/simd.rs @@ -0,0 +1,13 @@ +use core::simd::prelude::*; + +#[test] +fn testing() { + let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]); + let y = -x; + + let h = x * f32x4::splat(0.5); + + let r = y.abs(); + assert_eq!(x, r); + assert_eq!(h, f32x4::splat(0.5)); +} diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs new file mode 100644 index 00000000000..510dd4967c9 --- /dev/null +++ b/library/coretests/tests/slice.rs @@ -0,0 +1,2688 @@ +use core::cell::Cell; +use core::cmp::Ordering; +use core::mem::MaybeUninit; +use core::num::NonZero; +use core::ops::{Range, RangeInclusive}; +use core::slice; + +#[test] +fn test_position() { + let b = [1, 2, 3, 5, 5]; + assert_eq!(b.iter().position(|&v| v == 9), None); + assert_eq!(b.iter().position(|&v| v == 5), Some(3)); + assert_eq!(b.iter().position(|&v| v == 3), Some(2)); + assert_eq!(b.iter().position(|&v| v == 0), None); +} + +#[test] +fn test_rposition() { + let b = [1, 2, 3, 5, 5]; + assert_eq!(b.iter().rposition(|&v| v == 9), None); + assert_eq!(b.iter().rposition(|&v| v == 5), Some(4)); + assert_eq!(b.iter().rposition(|&v| v == 3), Some(2)); + assert_eq!(b.iter().rposition(|&v| v == 0), None); +} + +#[test] +fn test_binary_search() { + let b: [i32; 0] = []; + assert_eq!(b.binary_search(&5), Err(0)); + + let b = [4]; + assert_eq!(b.binary_search(&3), Err(0)); + assert_eq!(b.binary_search(&4), Ok(0)); + assert_eq!(b.binary_search(&5), Err(1)); + + let b = [1, 2, 4, 6, 8, 9]; + assert_eq!(b.binary_search(&5), Err(3)); + assert_eq!(b.binary_search(&6), Ok(3)); + assert_eq!(b.binary_search(&7), Err(4)); + assert_eq!(b.binary_search(&8), Ok(4)); + + let b = [1, 2, 4, 5, 6, 8]; + assert_eq!(b.binary_search(&9), Err(6)); + + let b = [1, 2, 4, 6, 7, 8, 9]; + assert_eq!(b.binary_search(&6), Ok(3)); + assert_eq!(b.binary_search(&5), Err(3)); + assert_eq!(b.binary_search(&8), Ok(5)); + + let b = [1, 2, 4, 5, 6, 8, 9]; + assert_eq!(b.binary_search(&7), Err(5)); + assert_eq!(b.binary_search(&0), Err(0)); + + let b = [1, 3, 3, 3, 7]; + assert_eq!(b.binary_search(&0), Err(0)); + assert_eq!(b.binary_search(&1), Ok(0)); + assert_eq!(b.binary_search(&2), Err(1)); + assert!(match b.binary_search(&3) { + Ok(1..=3) => true, + _ => false, + }); + assert!(match b.binary_search(&3) { + Ok(1..=3) => true, + _ => false, + }); + assert_eq!(b.binary_search(&4), Err(4)); + assert_eq!(b.binary_search(&5), Err(4)); + assert_eq!(b.binary_search(&6), Err(4)); + assert_eq!(b.binary_search(&7), Ok(4)); + assert_eq!(b.binary_search(&8), Err(5)); + + let b = [(); usize::MAX]; + assert_eq!(b.binary_search(&()), Ok(usize::MAX - 1)); +} + +#[test] +fn test_binary_search_by_overflow() { + let b = [(); usize::MAX]; + assert_eq!(b.binary_search_by(|_| Ordering::Equal), Ok(usize::MAX - 1)); + assert_eq!(b.binary_search_by(|_| Ordering::Greater), Err(0)); + assert_eq!(b.binary_search_by(|_| Ordering::Less), Err(usize::MAX)); +} + +#[test] +// Test implementation specific behavior when finding equivalent elements. +// It is ok to break this test but when you do a crater run is highly advisable. +fn test_binary_search_implementation_details() { + let b = [1, 1, 2, 2, 3, 3, 3]; + assert_eq!(b.binary_search(&1), Ok(1)); + assert_eq!(b.binary_search(&2), Ok(3)); + assert_eq!(b.binary_search(&3), Ok(6)); + let b = [1, 1, 1, 1, 1, 3, 3, 3, 3]; + assert_eq!(b.binary_search(&1), Ok(4)); + assert_eq!(b.binary_search(&3), Ok(8)); + let b = [1, 1, 1, 1, 3, 3, 3, 3, 3]; + assert_eq!(b.binary_search(&1), Ok(3)); + assert_eq!(b.binary_search(&3), Ok(8)); +} + +#[test] +fn test_partition_point() { + let b: [i32; 0] = []; + assert_eq!(b.partition_point(|&x| x < 5), 0); + + let b = [4]; + assert_eq!(b.partition_point(|&x| x < 3), 0); + assert_eq!(b.partition_point(|&x| x < 4), 0); + assert_eq!(b.partition_point(|&x| x < 5), 1); + + let b = [1, 2, 4, 6, 8, 9]; + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 7), 4); + assert_eq!(b.partition_point(|&x| x < 8), 4); + + let b = [1, 2, 4, 5, 6, 8]; + assert_eq!(b.partition_point(|&x| x < 9), 6); + + let b = [1, 2, 4, 6, 7, 8, 9]; + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 8), 5); + + let b = [1, 2, 4, 5, 6, 8, 9]; + assert_eq!(b.partition_point(|&x| x < 7), 5); + assert_eq!(b.partition_point(|&x| x < 0), 0); + + let b = [1, 3, 3, 3, 7]; + assert_eq!(b.partition_point(|&x| x < 0), 0); + assert_eq!(b.partition_point(|&x| x < 1), 0); + assert_eq!(b.partition_point(|&x| x < 2), 1); + assert_eq!(b.partition_point(|&x| x < 3), 1); + assert_eq!(b.partition_point(|&x| x < 4), 4); + assert_eq!(b.partition_point(|&x| x < 5), 4); + assert_eq!(b.partition_point(|&x| x < 6), 4); + assert_eq!(b.partition_point(|&x| x < 7), 4); + assert_eq!(b.partition_point(|&x| x < 8), 5); +} + +#[test] +fn test_iterator_advance_by() { + let v = &[0, 1, 2, 3, 4]; + + for i in 0..=v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.as_slice(), &v[i..]); + } + + let mut iter = v.iter(); + assert_eq!(iter.advance_by(v.len() + 1), Err(NonZero::new(1).unwrap())); + assert_eq!(iter.as_slice(), &[]); + + let mut iter = v.iter(); + assert_eq!(iter.advance_by(3), Ok(())); + assert_eq!(iter.as_slice(), &v[3..]); + assert_eq!(iter.advance_by(2), Ok(())); + assert_eq!(iter.as_slice(), &[]); + assert_eq!(iter.advance_by(0), Ok(())); +} + +#[test] +fn test_iterator_advance_back_by() { + let v = &[0, 1, 2, 3, 4]; + + for i in 0..=v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.as_slice(), &v[..v.len() - i]); + } + + let mut iter = v.iter(); + assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZero::new(1).unwrap())); + assert_eq!(iter.as_slice(), &[]); + + let mut iter = v.iter(); + assert_eq!(iter.advance_back_by(3), Ok(())); + assert_eq!(iter.as_slice(), &v[..v.len() - 3]); + assert_eq!(iter.advance_back_by(2), Ok(())); + assert_eq!(iter.as_slice(), &[]); + assert_eq!(iter.advance_back_by(0), Ok(())); +} + +#[test] +fn test_iterator_nth() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().nth(i).unwrap(), &v[i]); + } + assert_eq!(v.iter().nth(v.len()), None); + + let mut iter = v.iter(); + assert_eq!(iter.nth(2).unwrap(), &v[2]); + assert_eq!(iter.nth(1).unwrap(), &v[4]); +} + +#[test] +fn test_iterator_nth_back() { + let v: &[_] = &[0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - i - 1]); + } + assert_eq!(v.iter().nth_back(v.len()), None); + + let mut iter = v.iter(); + assert_eq!(iter.nth_back(2).unwrap(), &v[2]); + assert_eq!(iter.nth_back(1).unwrap(), &v[0]); +} + +#[test] +fn test_iterator_last() { + let v: &[_] = &[0, 1, 2, 3, 4]; + assert_eq!(v.iter().last().unwrap(), &4); + assert_eq!(v[..1].iter().last().unwrap(), &0); +} + +#[test] +fn test_iterator_count() { + let v: &[_] = &[0, 1, 2, 3, 4]; + assert_eq!(v.iter().count(), 5); + + let mut iter2 = v.iter(); + iter2.next(); + iter2.next(); + assert_eq!(iter2.count(), 3); +} + +#[test] +fn test_chunks_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.chunks(3); + assert_eq!(c.count(), 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.chunks(2); + assert_eq!(c2.count(), 3); + + let v3: &[i32] = &[]; + let c3 = v3.chunks(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_chunks_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.chunks(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.chunks(3); + assert_eq!(c2.nth(1).unwrap(), &[3, 4]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_chunks_next() { + let v = [0, 1, 2, 3, 4, 5]; + let mut c = v.chunks(2); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next().unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + assert_eq!(c.next(), None); + + let v = [0, 1, 2, 3, 4, 5, 6, 7]; + let mut c = v.chunks(3); + assert_eq!(c.next().unwrap(), &[0, 1, 2]); + assert_eq!(c.next().unwrap(), &[3, 4, 5]); + assert_eq!(c.next().unwrap(), &[6, 7]); + assert_eq!(c.next(), None); +} + +#[test] +fn test_chunks_next_back() { + let v = [0, 1, 2, 3, 4, 5]; + let mut c = v.chunks(2); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + assert_eq!(c.next_back().unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[0, 1]); + assert_eq!(c.next_back(), None); + + let v = [0, 1, 2, 3, 4, 5, 6, 7]; + let mut c = v.chunks(3); + assert_eq!(c.next_back().unwrap(), &[6, 7]); + assert_eq!(c.next_back().unwrap(), &[3, 4, 5]); + assert_eq!(c.next_back().unwrap(), &[0, 1, 2]); + assert_eq!(c.next_back(), None); +} + +#[test] +fn test_chunks_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.chunks(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.chunks(3); + assert_eq!(c2.nth_back(1).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &[i32] = &[0, 1, 2, 3, 4]; + let mut c3 = v3.chunks(10); + assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]); + assert_eq!(c3.next(), None); + + let v4: &[i32] = &[0, 1, 2]; + let mut c4 = v4.chunks(10); + assert_eq!(c4.nth_back(1_000_000_000usize), None); +} + +#[test] +fn test_chunks_last() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.chunks(2); + assert_eq!(c.last().unwrap()[1], 5); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.chunks(2); + assert_eq!(c2.last().unwrap()[0], 4); +} + +#[test] +fn test_chunks_zip() { + let v1: &[i32] = &[0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let res = v1 + .chunks(2) + .zip(v2.chunks(2)) + .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) + .collect::>(); + assert_eq!(res, vec![14, 22, 14]); +} + +#[test] +fn test_chunks_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.chunks_mut(3); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.chunks_mut(2); + assert_eq!(c2.count(), 3); + + let v3: &mut [i32] = &mut []; + let c3 = v3.chunks_mut(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_chunks_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.chunks_mut(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.chunks_mut(3); + assert_eq!(c2.nth(1).unwrap(), &[3, 4]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_chunks_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.chunks_mut(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c1 = v1.chunks_mut(3); + assert_eq!(c1.nth_back(1).unwrap(), &[0, 1, 2]); + assert_eq!(c1.next(), None); + + let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c3 = v3.chunks_mut(10); + assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]); + assert_eq!(c3.next(), None); + + let v4: &mut [i32] = &mut [0, 1, 2]; + let mut c4 = v4.chunks_mut(10); + assert_eq!(c4.nth_back(1_000_000_000usize), None); +} + +#[test] +fn test_chunks_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.chunks_mut(2); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.chunks_mut(2); + assert_eq!(c2.last().unwrap(), &[4]); +} + +#[test] +fn test_chunks_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.chunks_mut(2).zip(v2.chunks(2)) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [13, 14, 19, 20, 14]); +} + +#[test] +fn test_chunks_mut_zip_aliasing() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let mut it = v1.chunks_mut(2).zip(v2.chunks(2)); + let first = it.next().unwrap(); + let _ = it.next().unwrap(); + assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); +} + +#[test] +fn test_chunks_exact_mut_zip_aliasing() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let mut it = v1.chunks_exact_mut(2).zip(v2.chunks(2)); + let first = it.next().unwrap(); + let _ = it.next().unwrap(); + assert_eq!(first, (&mut [0, 1][..], &[6, 7][..])); +} + +#[test] +fn test_rchunks_mut_zip_aliasing() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let mut it = v1.rchunks_mut(2).zip(v2.chunks(2)); + let first = it.next().unwrap(); + let _ = it.next().unwrap(); + assert_eq!(first, (&mut [3, 4][..], &[6, 7][..])); +} + +#[test] +fn test_rchunks_exact_mut_zip_aliasing() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let mut it = v1.rchunks_exact_mut(2).zip(v2.chunks(2)); + let first = it.next().unwrap(); + let _ = it.next().unwrap(); + assert_eq!(first, (&mut [3, 4][..], &[6, 7][..])); +} + +#[test] +fn test_chunks_exact_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.chunks_exact(3); + assert_eq!(c.count(), 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.chunks_exact(2); + assert_eq!(c2.count(), 2); + + let v3: &[i32] = &[]; + let c3 = v3.chunks_exact(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_chunks_exact_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.chunks_exact(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.chunks_exact(3); + assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_chunks_exact_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.chunks_exact(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.chunks_exact(3); + assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &[i32] = &[0, 1, 2, 3, 4]; + let mut c3 = v3.chunks_exact(10); + assert_eq!(c3.nth_back(0), None); +} + +#[test] +fn test_chunks_exact_last() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.chunks_exact(2); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.chunks_exact(2); + assert_eq!(c2.last().unwrap(), &[2, 3]); +} + +#[test] +fn test_chunks_exact_remainder() { + let v: &[i32] = &[0, 1, 2, 3, 4]; + let c = v.chunks_exact(2); + assert_eq!(c.remainder(), &[4]); +} + +#[test] +fn test_chunks_exact_zip() { + let v1: &[i32] = &[0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let res = v1 + .chunks_exact(2) + .zip(v2.chunks_exact(2)) + .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) + .collect::>(); + assert_eq!(res, vec![14, 22]); +} + +#[test] +fn test_chunks_exact_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.chunks_exact_mut(3); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.chunks_exact_mut(2); + assert_eq!(c2.count(), 2); + + let v3: &mut [i32] = &mut []; + let c3 = v3.chunks_exact_mut(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_chunks_exact_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.chunks_exact_mut(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.chunks_exact_mut(3); + assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_chunks_exact_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.chunks_exact_mut(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.chunks_exact_mut(3); + assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c3 = v3.chunks_exact_mut(10); + assert_eq!(c3.nth_back(0), None); +} + +#[test] +fn test_chunks_exact_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.chunks_exact_mut(2); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.chunks_exact_mut(2); + assert_eq!(c2.last().unwrap(), &[2, 3]); +} + +#[test] +fn test_chunks_exact_mut_remainder() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c = v.chunks_exact_mut(2); + assert_eq!(c.into_remainder(), &[4]); +} + +#[test] +fn test_chunks_exact_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.chunks_exact_mut(2).zip(v2.chunks_exact(2)) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [13, 14, 19, 20, 4]); +} + +#[test] +fn test_array_chunks_infer() { + let v: &[i32] = &[0, 1, 2, 3, 4, -4]; + let c = v.array_chunks(); + for &[a, b, c] in c { + assert_eq!(a + b + c, 3); + } + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let total = v2.array_chunks().map(|&[a, b]| a * b).sum::(); + assert_eq!(total, 2 * 3 + 4 * 5); +} + +#[test] +fn test_array_chunks_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.array_chunks::<3>(); + assert_eq!(c.count(), 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.array_chunks::<2>(); + assert_eq!(c2.count(), 2); + + let v3: &[i32] = &[]; + let c3 = v3.array_chunks::<2>(); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_array_chunks_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks::<2>(); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.array_chunks::<3>(); + assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_array_chunks_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks::<2>(); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.array_chunks::<3>(); + assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &[i32] = &[0, 1, 2, 3, 4]; + let mut c3 = v3.array_chunks::<10>(); + assert_eq!(c3.nth_back(0), None); +} + +#[test] +fn test_array_chunks_last() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.array_chunks::<2>(); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.array_chunks::<2>(); + assert_eq!(c2.last().unwrap(), &[2, 3]); +} + +#[test] +fn test_array_chunks_remainder() { + let v: &[i32] = &[0, 1, 2, 3, 4]; + let c = v.array_chunks::<2>(); + assert_eq!(c.remainder(), &[4]); +} + +#[test] +fn test_array_chunks_zip() { + let v1: &[i32] = &[0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let res = v1 + .array_chunks::<2>() + .zip(v2.array_chunks::<2>()) + .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) + .collect::>(); + assert_eq!(res, vec![14, 22]); +} + +#[test] +fn test_array_chunks_mut_infer() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + for a in v.array_chunks_mut() { + let sum = a.iter().sum::(); + *a = [sum; 3]; + } + assert_eq!(v, &[3, 3, 3, 12, 12, 12, 6]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + v2.array_chunks_mut().for_each(|[a, b]| core::mem::swap(a, b)); + assert_eq!(v2, &[1, 0, 3, 2, 5, 4, 6]); +} + +#[test] +fn test_array_chunks_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.array_chunks_mut::<3>(); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.array_chunks_mut::<2>(); + assert_eq!(c2.count(), 2); + + let v3: &mut [i32] = &mut []; + let c3 = v3.array_chunks_mut::<2>(); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_array_chunks_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks_mut::<2>(); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.array_chunks_mut::<3>(); + assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_array_chunks_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks_mut::<2>(); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.array_chunks_mut::<3>(); + assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c3 = v3.array_chunks_mut::<10>(); + assert_eq!(c3.nth_back(0), None); +} + +#[test] +fn test_array_chunks_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.array_chunks_mut::<2>(); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.array_chunks_mut::<2>(); + assert_eq!(c2.last().unwrap(), &[2, 3]); +} + +#[test] +fn test_array_chunks_mut_remainder() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c = v.array_chunks_mut::<2>(); + assert_eq!(c.into_remainder(), &[4]); +} + +#[test] +fn test_array_chunks_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.array_chunks_mut::<2>().zip(v2.array_chunks::<2>()) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [13, 14, 19, 20, 4]); +} + +#[test] +fn test_array_windows_infer() { + let v: &[i32] = &[0, 1, 0, 1]; + assert_eq!(v.array_windows::<2>().count(), 3); + let c = v.array_windows(); + for &[a, b] in c { + assert_eq!(a + b, 1); + } + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let total = v2.array_windows().map(|&[a, b, c]| a + b + c).sum::(); + assert_eq!(total, 3 + 6 + 9 + 12 + 15); +} + +#[test] +fn test_array_windows_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.array_windows::<3>(); + assert_eq!(c.count(), 4); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.array_windows::<6>(); + assert_eq!(c2.count(), 0); + + let v3: &[i32] = &[]; + let c3 = v3.array_windows::<2>(); + assert_eq!(c3.count(), 0); + + let v4: &[()] = &[(); usize::MAX]; + let c4 = v4.array_windows::<1>(); + assert_eq!(c4.count(), usize::MAX); +} + +#[test] +fn test_array_windows_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let snd = v.array_windows::<4>().nth(1); + assert_eq!(snd, Some(&[1, 2, 3, 4])); + let mut arr_windows = v.array_windows::<2>(); + assert_ne!(arr_windows.nth(0), arr_windows.nth(0)); + let last = v.array_windows::<3>().last(); + assert_eq!(last, Some(&[3, 4, 5])); +} + +#[test] +fn test_array_windows_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let snd = v.array_windows::<4>().nth_back(1); + assert_eq!(snd, Some(&[1, 2, 3, 4])); + let mut arr_windows = v.array_windows::<2>(); + assert_ne!(arr_windows.nth_back(0), arr_windows.nth_back(0)); +} + +#[test] +fn test_rchunks_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.rchunks(3); + assert_eq!(c.count(), 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.rchunks(2); + assert_eq!(c2.count(), 3); + + let v3: &[i32] = &[]; + let c3 = v3.rchunks(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_rchunks_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.rchunks(3); + assert_eq!(c2.nth(1).unwrap(), &[0, 1]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.rchunks(3); + assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]); + assert_eq!(c2.next_back(), None); +} + +#[test] +fn test_rchunks_next() { + let v = [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks(2); + assert_eq!(c.next().unwrap(), &[4, 5]); + assert_eq!(c.next().unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v = [0, 1, 2, 3, 4, 5, 6, 7]; + let mut c = v.rchunks(3); + assert_eq!(c.next().unwrap(), &[5, 6, 7]); + assert_eq!(c.next().unwrap(), &[2, 3, 4]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); +} + +#[test] +fn test_rchunks_next_back() { + let v = [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks(2); + assert_eq!(c.next_back().unwrap(), &[0, 1]); + assert_eq!(c.next_back().unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + assert_eq!(c.next_back(), None); + + let v = [0, 1, 2, 3, 4, 5, 6, 7]; + let mut c = v.rchunks(3); + assert_eq!(c.next_back().unwrap(), &[0, 1]); + assert_eq!(c.next_back().unwrap(), &[2, 3, 4]); + assert_eq!(c.next_back().unwrap(), &[5, 6, 7]); + assert_eq!(c.next_back(), None); +} + +#[test] +fn test_rchunks_last() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.rchunks(2); + assert_eq!(c.last().unwrap()[1], 1); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.rchunks(2); + assert_eq!(c2.last().unwrap()[0], 0); +} + +#[test] +fn test_rchunks_zip() { + let v1: &[i32] = &[0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let res = v1 + .rchunks(2) + .zip(v2.rchunks(2)) + .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) + .collect::>(); + assert_eq!(res, vec![26, 18, 6]); +} + +#[test] +fn test_rchunks_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.rchunks_mut(3); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.rchunks_mut(2); + assert_eq!(c2.count(), 3); + + let v3: &mut [i32] = &mut []; + let c3 = v3.rchunks_mut(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_rchunks_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_mut(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.rchunks_mut(3); + assert_eq!(c2.nth(1).unwrap(), &[0, 1]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_mut(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.rchunks_mut(3); + assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]); + assert_eq!(c2.next_back(), None); +} + +#[test] +fn test_rchunks_mut_next() { + let mut v = [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_mut(2); + assert_eq!(c.next().unwrap(), &mut [4, 5]); + assert_eq!(c.next().unwrap(), &mut [2, 3]); + assert_eq!(c.next().unwrap(), &mut [0, 1]); + assert_eq!(c.next(), None); + + let mut v = [0, 1, 2, 3, 4, 5, 6, 7]; + let mut c = v.rchunks_mut(3); + assert_eq!(c.next().unwrap(), &mut [5, 6, 7]); + assert_eq!(c.next().unwrap(), &mut [2, 3, 4]); + assert_eq!(c.next().unwrap(), &mut [0, 1]); + assert_eq!(c.next(), None); +} + +#[test] +fn test_rchunks_mut_next_back() { + let mut v = [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_mut(2); + assert_eq!(c.next_back().unwrap(), &mut [0, 1]); + assert_eq!(c.next_back().unwrap(), &mut [2, 3]); + assert_eq!(c.next_back().unwrap(), &mut [4, 5]); + assert_eq!(c.next_back(), None); + + let mut v = [0, 1, 2, 3, 4, 5, 6, 7]; + let mut c = v.rchunks_mut(3); + assert_eq!(c.next_back().unwrap(), &mut [0, 1]); + assert_eq!(c.next_back().unwrap(), &mut [2, 3, 4]); + assert_eq!(c.next_back().unwrap(), &mut [5, 6, 7]); + assert_eq!(c.next_back(), None); +} + +#[test] +fn test_rchunks_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.rchunks_mut(2); + assert_eq!(c.last().unwrap(), &[0, 1]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.rchunks_mut(2); + assert_eq!(c2.last().unwrap(), &[0]); +} + +#[test] +fn test_rchunks_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.rchunks_mut(2).zip(v2.rchunks(2)) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [6, 16, 17, 22, 23]); +} + +#[test] +fn test_rchunks_exact_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.rchunks_exact(3); + assert_eq!(c.count(), 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.rchunks_exact(2); + assert_eq!(c2.count(), 2); + + let v3: &[i32] = &[]; + let c3 = v3.rchunks_exact(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_rchunks_exact_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_exact(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.rchunks_exact(3); + assert_eq!(c2.nth(1).unwrap(), &[1, 2, 3]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_exact_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_exact(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.rchunks_exact(3); + assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_exact_last() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.rchunks_exact(2); + assert_eq!(c.last().unwrap(), &[0, 1]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.rchunks_exact(2); + assert_eq!(c2.last().unwrap(), &[1, 2]); +} + +#[test] +fn test_rchunks_exact_remainder() { + let v: &[i32] = &[0, 1, 2, 3, 4]; + let c = v.rchunks_exact(2); + assert_eq!(c.remainder(), &[0]); +} + +#[test] +fn test_rchunks_exact_zip() { + let v1: &[i32] = &[0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let res = v1 + .rchunks_exact(2) + .zip(v2.rchunks_exact(2)) + .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) + .collect::>(); + assert_eq!(res, vec![26, 18]); +} + +#[test] +fn test_rchunks_exact_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.rchunks_exact_mut(3); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.rchunks_exact_mut(2); + assert_eq!(c2.count(), 2); + + let v3: &mut [i32] = &mut []; + let c3 = v3.rchunks_exact_mut(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_rchunks_exact_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_exact_mut(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.rchunks_exact_mut(3); + assert_eq!(c2.nth(1).unwrap(), &[1, 2, 3]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_exact_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_exact_mut(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next_back().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.rchunks_exact_mut(3); + assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_exact_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.rchunks_exact_mut(2); + assert_eq!(c.last().unwrap(), &[0, 1]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.rchunks_exact_mut(2); + assert_eq!(c2.last().unwrap(), &[1, 2]); +} + +#[test] +fn test_rchunks_exact_mut_remainder() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c = v.rchunks_exact_mut(2); + assert_eq!(c.into_remainder(), &[0]); +} + +#[test] +fn test_rchunks_exact_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.rchunks_exact_mut(2).zip(v2.rchunks_exact(2)) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [0, 16, 17, 22, 23]); +} + +#[test] +fn chunks_mut_are_send_and_sync() { + use std::cell::Cell; + use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut}; + use std::sync::MutexGuard; + + fn assert_send_and_sync() + where + ChunksMut<'static, Cell>: Send, + ChunksMut<'static, MutexGuard<'static, u32>>: Sync, + ChunksExactMut<'static, Cell>: Send, + ChunksExactMut<'static, MutexGuard<'static, u32>>: Sync, + RChunksMut<'static, Cell>: Send, + RChunksMut<'static, MutexGuard<'static, u32>>: Sync, + RChunksExactMut<'static, Cell>: Send, + RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync, + { + } + + assert_send_and_sync(); +} + +#[test] +fn test_windows_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.windows(3); + assert_eq!(c.count(), 4); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.windows(6); + assert_eq!(c2.count(), 0); + + let v3: &[i32] = &[]; + let c3 = v3.windows(2); + assert_eq!(c3.count(), 0); + + let v4 = &[(); usize::MAX]; + let c4 = v4.windows(1); + assert_eq!(c4.count(), usize::MAX); +} + +#[test] +fn test_windows_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.windows(2); + assert_eq!(c.nth(2).unwrap()[1], 3); + assert_eq!(c.next().unwrap()[0], 3); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.windows(4); + assert_eq!(c2.nth(1).unwrap()[1], 2); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_windows_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.windows(2); + assert_eq!(c.nth_back(2).unwrap()[0], 2); + assert_eq!(c.next_back().unwrap()[1], 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.windows(4); + assert_eq!(c2.nth_back(1).unwrap()[1], 1); + assert_eq!(c2.next_back(), None); +} + +#[test] +fn test_windows_last() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.windows(2); + assert_eq!(c.last().unwrap()[1], 5); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.windows(2); + assert_eq!(c2.last().unwrap()[0], 3); +} + +#[test] +fn test_windows_zip() { + let v1: &[i32] = &[0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let res = v1 + .windows(2) + .zip(v2.windows(2)) + .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) + .collect::>(); + + assert_eq!(res, [14, 18, 22, 26]); +} + +#[test] +fn test_iter_ref_consistency() { + use std::fmt::Debug; + + fn test(x: T) { + let v: &[T] = &[x, x, x]; + let v_ptrs: [*const T; 3] = match v { + [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], + _ => unreachable!(), + }; + let len = v.len(); + + // nth(i) + for i in 0..len { + assert_eq!(&v[i] as *const _, v_ptrs[i]); // check the v_ptrs array, just to be sure + let nth = v.iter().nth(i).unwrap(); + assert_eq!(nth as *const _, v_ptrs[i]); + } + assert_eq!(v.iter().nth(len), None, "nth(len) should return None"); + + // stepping through with nth(0) + { + let mut it = v.iter(); + for i in 0..len { + let next = it.nth(0).unwrap(); + assert_eq!(next as *const _, v_ptrs[i]); + } + assert_eq!(it.nth(0), None); + } + + // next() + { + let mut it = v.iter(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let next = it.next().unwrap(); + assert_eq!(next as *const _, v_ptrs[i]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None, "The final call to next() should return None"); + } + + // next_back() + { + let mut it = v.iter(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let prev = it.next_back().unwrap(); + assert_eq!(prev as *const _, v_ptrs[remaining - 1]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); + } + } + + fn test_mut(x: T) { + let v: &mut [T] = &mut [x, x, x]; + let v_ptrs: [*mut T; 3] = match v { + [ref v1, ref v2, ref v3] => { + [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _] + } + _ => unreachable!(), + }; + let len = v.len(); + + // nth(i) + for i in 0..len { + assert_eq!(&mut v[i] as *mut _, v_ptrs[i]); // check the v_ptrs array, just to be sure + let nth = v.iter_mut().nth(i).unwrap(); + assert_eq!(nth as *mut _, v_ptrs[i]); + } + assert_eq!(v.iter().nth(len), None, "nth(len) should return None"); + + // stepping through with nth(0) + { + let mut it = v.iter(); + for i in 0..len { + let next = it.nth(0).unwrap(); + assert_eq!(next as *const _, v_ptrs[i]); + } + assert_eq!(it.nth(0), None); + } + + // next() + { + let mut it = v.iter_mut(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let next = it.next().unwrap(); + assert_eq!(next as *mut _, v_ptrs[i]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None, "The final call to next() should return None"); + } + + // next_back() + { + let mut it = v.iter_mut(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let prev = it.next_back().unwrap(); + assert_eq!(prev as *mut _, v_ptrs[remaining - 1]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); + } + } + + // Make sure iterators and slice patterns yield consistent addresses for various types, + // including ZSTs. + test(0u32); + test(()); + test([0u32; 0]); // ZST with alignment > 0 + test_mut(0u32); + test_mut(()); + test_mut([0u32; 0]); // ZST with alignment > 0 +} + +// The current implementation of SliceIndex fails to handle methods +// orthogonally from range types; therefore, it is worth testing +// all of the indexing operations on each input. +mod slice_index { + // This checks all six indexing methods, given an input range that + // should succeed. (it is NOT suitable for testing invalid inputs) + macro_rules! assert_range_eq { + ($arr:expr, $range:expr, $expected:expr) => { + let mut arr = $arr; + let mut expected = $expected; + { + let s: &[_] = &arr; + let expected: &[_] = &expected; + + assert_eq!(&s[$range], expected, "(in assertion for: index)"); + assert_eq!(s.get($range), Some(expected), "(in assertion for: get)"); + unsafe { + assert_eq!( + s.get_unchecked($range), + expected, + "(in assertion for: get_unchecked)", + ); + } + } + { + let s: &mut [_] = &mut arr; + let expected: &mut [_] = &mut expected; + + assert_eq!(&mut s[$range], expected, "(in assertion for: index_mut)",); + assert_eq!( + s.get_mut($range), + Some(&mut expected[..]), + "(in assertion for: get_mut)", + ); + unsafe { + assert_eq!( + s.get_unchecked_mut($range), + expected, + "(in assertion for: get_unchecked_mut)", + ); + } + } + }; + } + + // Make sure the macro can actually detect bugs, + // because if it can't, then what are we even doing here? + // + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method that panics, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "out of range")] + fn assert_range_eq_can_fail_by_panic() { + assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]); + } + + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method it calls, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "==")] + fn assert_range_eq_can_fail_by_inequality() { + assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]); + } + + // Test cases for bad index operations. + // + // This generates `should_panic` test cases for Index/IndexMut + // and `None` test cases for get/get_mut. + macro_rules! panic_cases { + ($( + // each test case needs a unique name to namespace the tests + in mod $case_name:ident { + data: $data:expr; + + // optional: + // + // one or more similar inputs for which data[input] succeeds, + // and the corresponding output as an array. This helps validate + // "critical points" where an input range straddles the boundary + // between valid and invalid. + // (such as the input `len..len`, which is just barely valid) + $( + good: data[$good:expr] == $output:expr; + )* + + bad: data[$bad:expr]; + message: $expect_msg:expr; + } + )*) => {$( + mod $case_name { + #[allow(unused_imports)] + use core::ops::Bound; + + #[test] + fn pass() { + let mut v = $data; + + $( assert_range_eq!($data, $good, $output); )* + + { + let v: &[_] = &v; + assert_eq!(v.get($bad), None, "(in None assertion for get)"); + } + + { + let v: &mut [_] = &mut v; + assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)"); + } + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_fail() { + let v = $data; + let v: &[_] = &v; + let _v = &v[$bad]; + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_mut_fail() { + let mut v = $data; + let v: &mut [_] = &mut v; + let _v = &mut v[$bad]; + } + } + )*}; + } + + #[test] + fn simple() { + let v = [0, 1, 2, 3, 4, 5]; + + assert_range_eq!(v, .., [0, 1, 2, 3, 4, 5]); + assert_range_eq!(v, ..2, [0, 1]); + assert_range_eq!(v, ..=1, [0, 1]); + assert_range_eq!(v, 2.., [2, 3, 4, 5]); + assert_range_eq!(v, 1..4, [1, 2, 3]); + assert_range_eq!(v, 1..=3, [1, 2, 3]); + } + + panic_cases! { + in mod rangefrom_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[6..] == []; + bad: data[7..]; + message: "out of range"; + } + + in mod rangeto_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[..6] == [0, 1, 2, 3, 4, 5]; + bad: data[..7]; + message: "out of range"; + } + + in mod rangetoinclusive_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[..=5] == [0, 1, 2, 3, 4, 5]; + bad: data[..=6]; + message: "out of range"; + } + + in mod rangeinclusive_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[0..=5] == [0, 1, 2, 3, 4, 5]; + bad: data[0..=6]; + message: "out of range"; + } + + in mod range_len_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[6..6] == []; + bad: data[7..7]; + message: "out of range"; + } + + in mod rangeinclusive_len_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[6..=5] == []; + bad: data[7..=6]; + message: "out of range"; + } + + in mod boundpair_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[(Bound::Included(6), Bound::Unbounded)] == []; + good: data[(Bound::Unbounded, Bound::Included(5))] == [0, 1, 2, 3, 4, 5]; + good: data[(Bound::Unbounded, Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5]; + good: data[(Bound::Included(0), Bound::Included(5))] == [0, 1, 2, 3, 4, 5]; + good: data[(Bound::Included(0), Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5]; + good: data[(Bound::Included(2), Bound::Excluded(4))] == [2, 3]; + good: data[(Bound::Excluded(1), Bound::Included(4))] == [2, 3, 4]; + good: data[(Bound::Excluded(5), Bound::Excluded(6))] == []; + good: data[(Bound::Included(6), Bound::Excluded(6))] == []; + good: data[(Bound::Excluded(5), Bound::Included(5))] == []; + good: data[(Bound::Included(6), Bound::Included(5))] == []; + bad: data[(Bound::Unbounded, Bound::Included(6))]; + message: "out of range"; + } + } + + panic_cases! { + in mod rangeinclusive_exhausted { + data: [0, 1, 2, 3, 4, 5]; + + good: data[0..=5] == [0, 1, 2, 3, 4, 5]; + good: data[{ + let mut iter = 0..=5; + iter.by_ref().count(); // exhaust it + iter + }] == []; + + // 0..=6 is out of range before exhaustion, so it + // stands to reason that it still would be after. + bad: data[{ + let mut iter = 0..=6; + iter.by_ref().count(); // exhaust it + iter + }]; + message: "out of range"; + } + } + + panic_cases! { + in mod range_neg_width { + data: [0, 1, 2, 3, 4, 5]; + + good: data[4..4] == []; + bad: data[4..3]; + message: "but ends at"; + } + + in mod rangeinclusive_neg_width { + data: [0, 1, 2, 3, 4, 5]; + + good: data[4..=3] == []; + bad: data[4..=2]; + message: "but ends at"; + } + + in mod boundpair_neg_width { + data: [0, 1, 2, 3, 4, 5]; + + good: data[(Bound::Included(4), Bound::Excluded(4))] == []; + bad: data[(Bound::Included(4), Bound::Excluded(3))]; + message: "but ends at"; + } + } + + panic_cases! { + in mod rangeinclusive_overflow { + data: [0, 1]; + + // note: using 0 specifically ensures that the result of overflowing is 0..0, + // so that `get` doesn't simply return None for the wrong reason. + bad: data[0 ..= usize::MAX]; + message: "maximum usize"; + } + + in mod rangetoinclusive_overflow { + data: [0, 1]; + + bad: data[..= usize::MAX]; + message: "maximum usize"; + } + + in mod boundpair_overflow_end { + data: [0; 1]; + + bad: data[(Bound::Unbounded, Bound::Included(usize::MAX))]; + message: "maximum usize"; + } + + in mod boundpair_overflow_start { + data: [0; 1]; + + bad: data[(Bound::Excluded(usize::MAX), Bound::Unbounded)]; + message: "maximum usize"; + } + } // panic_cases! +} + +#[test] +fn test_find_rfind() { + let v = [0, 1, 2, 3, 4, 5]; + let mut iter = v.iter(); + let mut i = v.len(); + while let Some(&elt) = iter.rfind(|_| true) { + i -= 1; + assert_eq!(elt, v[i]); + } + assert_eq!(i, 0); + assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3)); +} + +#[test] +fn test_iter_folds() { + let a = [1, 2, 3, 4, 5]; // len>4 so the unroll is used + assert_eq!(a.iter().fold(0, |acc, &x| 2 * acc + x), 57); + assert_eq!(a.iter().rfold(0, |acc, &x| 2 * acc + x), 129); + let fold = |acc: i32, &x| acc.checked_mul(2)?.checked_add(x); + assert_eq!(a.iter().try_fold(0, &fold), Some(57)); + assert_eq!(a.iter().try_rfold(0, &fold), Some(129)); + + // short-circuiting try_fold, through other methods + let a = [0, 1, 2, 3, 5, 5, 5, 7, 8, 9]; + let mut iter = a.iter(); + assert_eq!(iter.position(|&x| x == 3), Some(3)); + assert_eq!(iter.rfind(|&&x| x == 5), Some(&5)); + assert_eq!(iter.len(), 2); +} + +#[test] +fn test_rotate_left() { + const N: usize = 600; + let a: &mut [_] = &mut [0; N]; + for i in 0..N { + a[i] = i; + } + + a.rotate_left(42); + let k = N - 42; + + for i in 0..N { + assert_eq!(a[(i + k) % N], i); + } +} + +#[test] +fn test_rotate_right() { + const N: usize = 600; + let a: &mut [_] = &mut [0; N]; + for i in 0..N { + a[i] = i; + } + + a.rotate_right(42); + + for i in 0..N { + assert_eq!(a[(i + 42) % N], i); + } +} + +#[test] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn brute_force_rotate_test_0() { + // In case of edge cases involving multiple algorithms + let n = 300; + for len in 0..n { + for s in 0..len { + let mut v = Vec::with_capacity(len); + for i in 0..len { + v.push(i); + } + v[..].rotate_right(s); + for i in 0..v.len() { + assert_eq!(v[i], v.len().wrapping_add(i.wrapping_sub(s)) % v.len()); + } + } + } +} + +#[test] +fn brute_force_rotate_test_1() { + // `ptr_rotate` covers so many kinds of pointer usage, that this is just a good test for + // pointers in general. This uses a `[usize; 4]` to hit all algorithms without overwhelming miri + let n = 30; + for len in 0..n { + for s in 0..len { + let mut v: Vec<[usize; 4]> = Vec::with_capacity(len); + for i in 0..len { + v.push([i, 0, 0, 0]); + } + v[..].rotate_right(s); + for i in 0..v.len() { + assert_eq!(v[i][0], v.len().wrapping_add(i.wrapping_sub(s)) % v.len()); + } + } + } +} + +#[test] +#[cfg(not(target_arch = "wasm32"))] +#[cfg_attr(miri, ignore)] // Miri is too slow +fn select_nth_unstable() { + use core::cmp::Ordering::{Equal, Greater, Less}; + + use rand::Rng; + use rand::seq::SliceRandom; + + let mut rng = crate::test_rng(); + + for len in (2..21).chain(500..501) { + let mut orig = vec![0; len]; + + for &modulus in &[5, 10, 1000] { + for _ in 0..10 { + for i in 0..len { + orig[i] = rng.gen::() % modulus; + } + + let v_sorted = { + let mut v = orig.clone(); + v.sort(); + v + }; + + // Sort in default order. + for pivot in 0..len { + let mut v = orig.clone(); + v.select_nth_unstable(pivot); + + assert_eq!(v_sorted[pivot], v[pivot]); + for i in 0..pivot { + for j in pivot..len { + assert!(v[i] <= v[j]); + } + } + } + + // Sort in ascending order. + for pivot in 0..len { + let mut v = orig.clone(); + let (left, pivot, right) = v.select_nth_unstable_by(pivot, |a, b| a.cmp(b)); + + assert_eq!(left.len() + right.len(), len - 1); + + for l in left { + assert!(l <= pivot); + for r in right.iter_mut() { + assert!(l <= r); + assert!(pivot <= r); + } + } + } + + // Sort in descending order. + let sort_descending_comparator = |a: &i32, b: &i32| b.cmp(a); + let v_sorted_descending = { + let mut v = orig.clone(); + v.sort_by(sort_descending_comparator); + v + }; + + for pivot in 0..len { + let mut v = orig.clone(); + v.select_nth_unstable_by(pivot, sort_descending_comparator); + + assert_eq!(v_sorted_descending[pivot], v[pivot]); + for i in 0..pivot { + for j in pivot..len { + assert!(v[j] <= v[i]); + } + } + } + } + } + } + + // Sort at index using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + let mut v = [0; 500]; + for i in 0..v.len() { + v[i] = i as i32; + } + + for pivot in 0..v.len() { + v.select_nth_unstable_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); + v.sort(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + } + + // Should not panic. + [(); 10].select_nth_unstable(0); + [(); 10].select_nth_unstable(5); + [(); 10].select_nth_unstable(9); + [(); 100].select_nth_unstable(0); + [(); 100].select_nth_unstable(50); + [(); 100].select_nth_unstable(99); + + let mut v = [0xDEADBEEFu64]; + v.select_nth_unstable(0); + assert!(v == [0xDEADBEEF]); +} + +#[test] +#[should_panic(expected = "index 0 greater than length of slice")] +fn select_nth_unstable_zero_length() { + [0i32; 0].select_nth_unstable(0); +} + +#[test] +#[should_panic(expected = "index 20 greater than length of slice")] +fn select_nth_unstable_past_length() { + [0i32; 10].select_nth_unstable(20); +} + +pub mod memchr { + use core::slice::memchr::{memchr, memrchr}; + + // test fallback implementations on all platforms + #[test] + fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); + } + + #[test] + fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); + } + + #[test] + fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); + } + + #[test] + fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); + } + + #[test] + fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); + } + + #[test] + fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); + } + + #[test] + fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); + } + + #[test] + fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); + } + + #[test] + fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); + } + + #[test] + fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); + } + + #[test] + fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } + } +} + +#[test] +fn test_align_to_simple() { + let bytes = [1u8, 2, 3, 4, 5, 6, 7]; + let (prefix, aligned, suffix) = unsafe { bytes.align_to::() }; + assert_eq!(aligned.len(), 3); + assert!(prefix == [1] || suffix == [7]); + let expect1 = [1 << 8 | 2, 3 << 8 | 4, 5 << 8 | 6]; + let expect2 = [1 | 2 << 8, 3 | 4 << 8, 5 | 6 << 8]; + let expect3 = [2 << 8 | 3, 4 << 8 | 5, 6 << 8 | 7]; + let expect4 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8]; + assert!( + aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4, + "aligned={:?} expected={:?} || {:?} || {:?} || {:?}", + aligned, + expect1, + expect2, + expect3, + expect4 + ); +} + +#[test] +fn test_align_to_zst() { + let bytes = [1, 2, 3, 4, 5, 6, 7]; + let (prefix, aligned, suffix) = unsafe { bytes.align_to::<()>() }; + assert_eq!(aligned.len(), 0); + assert!(prefix == [1, 2, 3, 4, 5, 6, 7] || suffix == [1, 2, 3, 4, 5, 6, 7]); +} + +#[test] +fn test_align_to_non_trivial() { + #[repr(align(8))] + struct U64(#[allow(dead_code)] u64, #[allow(dead_code)] u64); + #[repr(align(8))] + struct U64U64U32(#[allow(dead_code)] u64, #[allow(dead_code)] u64, #[allow(dead_code)] u32); + let data = [ + U64(1, 2), + U64(3, 4), + U64(5, 6), + U64(7, 8), + U64(9, 10), + U64(11, 12), + U64(13, 14), + U64(15, 16), + ]; + let (prefix, aligned, suffix) = unsafe { data.align_to::() }; + assert_eq!(aligned.len(), 4); + assert_eq!(prefix.len() + suffix.len(), 2); +} + +#[test] +fn test_align_to_empty_mid() { + use core::mem; + + // Make sure that we do not create empty unaligned slices for the mid part, even when the + // overall slice is too short to contain an aligned address. + let bytes = [1, 2, 3, 4, 5, 6, 7]; + type Chunk = u32; + for offset in 0..4 { + let (_, mid, _) = unsafe { bytes[offset..offset + 1].align_to::() }; + assert_eq!(mid.as_ptr() as usize % mem::align_of::(), 0); + } +} + +#[test] +fn test_align_to_mut_aliasing() { + let mut val = [1u8, 2, 3, 4, 5]; + // `align_to_mut` used to create `mid` in a way that there was some intermediate + // incorrect aliasing, invalidating the resulting `mid` slice. + let (begin, mid, end) = unsafe { val.align_to_mut::<[u8; 2]>() }; + assert!(begin.len() == 0); + assert!(end.len() == 1); + mid[0] = mid[1]; + assert_eq!(val, [3, 4, 3, 4, 5]) +} + +#[test] +fn test_slice_partition_dedup_by() { + let mut slice: [i32; 9] = [1, -1, 2, 3, 1, -5, 5, -2, 2]; + + let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.abs() == b.abs()); + + assert_eq!(dedup, [1, 2, 3, 1, -5, -2]); + assert_eq!(duplicates, [5, -1, 2]); +} + +#[test] +fn test_slice_partition_dedup_empty() { + let mut slice: [i32; 0] = []; + + let (dedup, duplicates) = slice.partition_dedup(); + + assert_eq!(dedup, []); + assert_eq!(duplicates, []); +} + +#[test] +fn test_slice_partition_dedup_one() { + let mut slice = [12]; + + let (dedup, duplicates) = slice.partition_dedup(); + + assert_eq!(dedup, [12]); + assert_eq!(duplicates, []); +} + +#[test] +fn test_slice_partition_dedup_multiple_ident() { + let mut slice = [12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11]; + + let (dedup, duplicates) = slice.partition_dedup(); + + assert_eq!(dedup, [12, 11]); + assert_eq!(duplicates, [12, 12, 12, 12, 11, 11, 11, 11, 11]); +} + +#[test] +fn test_slice_partition_dedup_partialeq() { + #[derive(Debug)] + struct Foo(i32, #[allow(dead_code)] i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.0 == other.0 + } + } + + let mut slice = [Foo(0, 1), Foo(0, 5), Foo(1, 7), Foo(1, 9)]; + + let (dedup, duplicates) = slice.partition_dedup(); + + assert_eq!(dedup, [Foo(0, 1), Foo(1, 7)]); + assert_eq!(duplicates, [Foo(0, 5), Foo(1, 9)]); +} + +#[test] +fn test_copy_within() { + // Start to end, with a RangeTo. + let mut bytes = *b"Hello, World!"; + bytes.copy_within(..3, 10); + assert_eq!(&bytes, b"Hello, WorHel"); + + // End to start, with a RangeFrom. + let mut bytes = *b"Hello, World!"; + bytes.copy_within(10.., 0); + assert_eq!(&bytes, b"ld!lo, World!"); + + // Overlapping, with a RangeInclusive. + let mut bytes = *b"Hello, World!"; + bytes.copy_within(0..=11, 1); + assert_eq!(&bytes, b"HHello, World"); + + // Whole slice, with a RangeFull. + let mut bytes = *b"Hello, World!"; + bytes.copy_within(.., 0); + assert_eq!(&bytes, b"Hello, World!"); + + // Ensure that copying at the end of slice won't cause UB. + let mut bytes = *b"Hello, World!"; + bytes.copy_within(13..13, 5); + assert_eq!(&bytes, b"Hello, World!"); + bytes.copy_within(5..5, 13); + assert_eq!(&bytes, b"Hello, World!"); +} + +#[test] +#[should_panic(expected = "range end index 14 out of range for slice of length 13")] +fn test_copy_within_panics_src_too_long() { + let mut bytes = *b"Hello, World!"; + // The length is only 13, so 14 is out of bounds. + bytes.copy_within(10..14, 0); +} + +#[test] +#[should_panic(expected = "dest is out of bounds")] +fn test_copy_within_panics_dest_too_long() { + let mut bytes = *b"Hello, World!"; + // The length is only 13, so a slice of length 4 starting at index 10 is out of bounds. + bytes.copy_within(0..4, 10); +} + +#[test] +#[should_panic(expected = "slice index starts at 2 but ends at 1")] +fn test_copy_within_panics_src_inverted() { + let mut bytes = *b"Hello, World!"; + // 2 is greater than 1, so this range is invalid. + bytes.copy_within(2..1, 0); +} +#[test] +#[should_panic(expected = "attempted to index slice up to maximum usize")] +fn test_copy_within_panics_src_out_of_bounds() { + let mut bytes = *b"Hello, World!"; + // an inclusive range ending at usize::MAX would make src_end overflow + bytes.copy_within(usize::MAX..=usize::MAX, 0); +} + +#[test] +fn test_is_sorted() { + let empty: [i32; 0] = []; + + // Tests on integers + assert!([1, 2, 2, 9].is_sorted()); + assert!(![1, 3, 2].is_sorted()); + assert!([0].is_sorted()); + assert!([0, 0].is_sorted()); + assert!(empty.is_sorted()); + + // Tests on floats + assert!([1.0f32, 2.0, 2.0, 9.0].is_sorted()); + assert!(![1.0f32, 3.0f32, 2.0f32].is_sorted()); + assert!([0.0f32].is_sorted()); + assert!([0.0f32, 0.0f32].is_sorted()); + // Test cases with NaNs + assert!([f32::NAN].is_sorted()); + assert!(![f32::NAN, f32::NAN].is_sorted()); + assert!(![0.0, 1.0, f32::NAN].is_sorted()); + // Tests from + assert!(![f32::NAN, f32::NAN, f32::NAN].is_sorted()); + assert!(![1.0, f32::NAN, 2.0].is_sorted()); + assert!(![2.0, f32::NAN, 1.0].is_sorted()); + assert!(![2.0, f32::NAN, 1.0, 7.0].is_sorted()); + assert!(![2.0, f32::NAN, 1.0, 0.0].is_sorted()); + assert!(![-f32::NAN, -1.0, 0.0, 1.0, f32::NAN].is_sorted()); + assert!(![f32::NAN, -f32::NAN, -1.0, 0.0, 1.0].is_sorted()); + assert!(![1.0, f32::NAN, -f32::NAN, -1.0, 0.0].is_sorted()); + assert!(![0.0, 1.0, f32::NAN, -f32::NAN, -1.0].is_sorted()); + assert!(![-1.0, 0.0, 1.0, f32::NAN, -f32::NAN].is_sorted()); + + // Tests for is_sorted_by + assert!(![6, 2, 8, 5, 1, -60, 1337].is_sorted()); + assert!([6, 2, 8, 5, 1, -60, 1337].is_sorted_by(|_, _| true)); + + // Tests for is_sorted_by_key + assert!([-2, -1, 0, 3].is_sorted()); + assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); + assert!(!["c", "bb", "aaa"].is_sorted()); + assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); +} + +#[test] +fn test_slice_run_destructors() { + // Make sure that destructors get run on slice literals + struct Foo<'a> { + x: &'a Cell, + } + + impl<'a> Drop for Foo<'a> { + fn drop(&mut self) { + self.x.set(self.x.get() + 1); + } + } + + fn foo(x: &Cell) -> Foo<'_> { + Foo { x } + } + + let x = &Cell::new(0); + + { + let l = &[foo(x)]; + assert_eq!(l[0].x.get(), 0); + } + + assert_eq!(x.get(), 1); +} + +#[test] +fn test_const_from_ref() { + const VALUE: &i32 = &1; + const SLICE: &[i32] = core::slice::from_ref(VALUE); + + assert!(core::ptr::eq(VALUE, &SLICE[0])) +} + +#[test] +fn test_slice_fill_with_uninit() { + // This should not UB. See #87891 + let mut a = [MaybeUninit::::uninit(); 10]; + a.fill(MaybeUninit::uninit()); +} + +#[test] +fn test_swap() { + let mut x = ["a", "b", "c", "d"]; + x.swap(1, 3); + assert_eq!(x, ["a", "d", "c", "b"]); + x.swap(0, 3); + assert_eq!(x, ["b", "d", "c", "a"]); +} + +mod swap_panics { + #[test] + #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")] + fn index_a_equals_len() { + let mut x = ["a", "b", "c", "d"]; + x.swap(4, 2); + } + + #[test] + #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")] + fn index_b_equals_len() { + let mut x = ["a", "b", "c", "d"]; + x.swap(2, 4); + } + + #[test] + #[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")] + fn index_a_greater_than_len() { + let mut x = ["a", "b", "c", "d"]; + x.swap(5, 2); + } + + #[test] + #[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")] + fn index_b_greater_than_len() { + let mut x = ["a", "b", "c", "d"]; + x.swap(2, 5); + } +} + +#[test] +fn slice_split_first_chunk_mut() { + let v = &mut [1, 2, 3, 4, 5, 6][..]; + + { + let (left, right) = v.split_first_chunk_mut::<0>().unwrap(); + assert_eq!(left, &mut []); + assert_eq!(right, [1, 2, 3, 4, 5, 6]); + } + + { + let (left, right) = v.split_first_chunk_mut::<6>().unwrap(); + assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); + assert_eq!(right, []); + } + + { + assert!(v.split_first_chunk_mut::<7>().is_none()); + } +} + +#[test] +fn slice_split_last_chunk_mut() { + let v = &mut [1, 2, 3, 4, 5, 6][..]; + + { + let (left, right) = v.split_last_chunk_mut::<0>().unwrap(); + assert_eq!(left, [1, 2, 3, 4, 5, 6]); + assert_eq!(right, &mut []); + } + + { + let (left, right) = v.split_last_chunk_mut::<6>().unwrap(); + assert_eq!(left, []); + assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); + } + + { + assert!(v.split_last_chunk_mut::<7>().is_none()); + } +} + +#[test] +fn split_as_slice() { + let arr = [1, 2, 3, 4, 5, 6]; + let mut split = arr.split(|v| v % 2 == 0); + assert_eq!(split.as_slice(), &[1, 2, 3, 4, 5, 6]); + assert!(split.next().is_some()); + assert_eq!(split.as_slice(), &[3, 4, 5, 6]); + assert!(split.next().is_some()); + assert!(split.next().is_some()); + assert_eq!(split.as_slice(), &[]); +} + +#[test] +fn slice_split_once() { + let v = &[1, 2, 3, 2, 4][..]; + + assert_eq!(v.split_once(|&x| x == 2), Some((&[1][..], &[3, 2, 4][..]))); + assert_eq!(v.split_once(|&x| x == 1), Some((&[][..], &[2, 3, 2, 4][..]))); + assert_eq!(v.split_once(|&x| x == 4), Some((&[1, 2, 3, 2][..], &[][..]))); + assert_eq!(v.split_once(|&x| x == 0), None); +} + +#[test] +fn slice_rsplit_once() { + let v = &[1, 2, 3, 2, 4][..]; + + assert_eq!(v.rsplit_once(|&x| x == 2), Some((&[1, 2, 3][..], &[4][..]))); + assert_eq!(v.rsplit_once(|&x| x == 1), Some((&[][..], &[2, 3, 2, 4][..]))); + assert_eq!(v.rsplit_once(|&x| x == 4), Some((&[1, 2, 3, 2][..], &[][..]))); + assert_eq!(v.rsplit_once(|&x| x == 0), None); +} + +macro_rules! take_tests { + (slice: &[], $($tts:tt)*) => { + take_tests!(ty: &[()], slice: &[], $($tts)*); + }; + (slice: &mut [], $($tts:tt)*) => { + take_tests!(ty: &mut [()], slice: &mut [], $($tts)*); + }; + (slice: &$slice:expr, $($tts:tt)*) => { + take_tests!(ty: &[_], slice: &$slice, $($tts)*); + }; + (slice: &mut $slice:expr, $($tts:tt)*) => { + take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*); + }; + (ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => { + $( + #[test] + fn $test_name() { + let mut slice: $ty = $slice; + assert_eq!($output, slice.$method($($args)*)); + let remaining: $ty = $remaining; + assert_eq!(remaining, slice); + } + )* + }; +} + +take_tests! { + slice: &[0, 1, 2, 3], method: take, + (take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]), + (take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]), + (take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]), + (take_oob_range_to, (..5), None, &[0, 1, 2, 3]), + (take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]), + (take_oob_range_from, (5..), None, &[0, 1, 2, 3]), +} + +take_tests! { + slice: &mut [0, 1, 2, 3], method: take_mut, + (take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]), + (take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]), + (take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]), + (take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]), + (take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]), + (take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]), +} + +take_tests! { + slice: &[1, 2], method: take_first, + (take_first_nonempty, (), Some(&1), &[2]), +} + +take_tests! { + slice: &mut [1, 2], method: take_first_mut, + (take_first_mut_nonempty, (), Some(&mut 1), &mut [2]), +} + +take_tests! { + slice: &[1, 2], method: take_last, + (take_last_nonempty, (), Some(&2), &[1]), +} + +take_tests! { + slice: &mut [1, 2], method: take_last_mut, + (take_last_mut_nonempty, (), Some(&mut 2), &mut [1]), +} + +take_tests! { + slice: &[], method: take_first, + (take_first_empty, (), None, &[]), +} + +take_tests! { + slice: &mut [], method: take_first_mut, + (take_first_mut_empty, (), None, &mut []), +} + +take_tests! { + slice: &[], method: take_last, + (take_last_empty, (), None, &[]), +} + +take_tests! { + slice: &mut [], method: take_last_mut, + (take_last_mut_empty, (), None, &mut []), +} + +#[cfg(not(miri))] // unused in Miri +const EMPTY_MAX: &'static [()] = &[(); usize::MAX]; + +// can't be a constant due to const mutability rules +#[cfg(not(miri))] // unused in Miri +macro_rules! empty_max_mut { + () => { + &mut [(); usize::MAX] as _ + }; +} + +#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) +take_tests! { + slice: &[(); usize::MAX], method: take, + (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]), + (take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX), + (take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX), +} + +#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) +take_tests! { + slice: &mut [(); usize::MAX], method: take_mut, + (take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]), + (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), + (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), +} + +#[test] +fn test_slice_from_ptr_range() { + let arr = ["foo".to_owned(), "bar".to_owned()]; + let range = arr.as_ptr_range(); + unsafe { + assert_eq!(slice::from_ptr_range(range), &arr); + } + + let mut arr = [1, 2, 3]; + let range = arr.as_mut_ptr_range(); + unsafe { + assert_eq!(slice::from_mut_ptr_range(range), &mut [1, 2, 3]); + } + + let arr: [Vec; 0] = []; + let range = arr.as_ptr_range(); + unsafe { + assert_eq!(slice::from_ptr_range(range), &arr); + } +} + +#[test] +#[should_panic = "slice len overflow"] +fn test_flatten_size_overflow() { + let x = &[[(); usize::MAX]; 2][..]; + let _ = x.as_flattened(); +} + +#[test] +#[should_panic = "slice len overflow"] +fn test_flatten_mut_size_overflow() { + let x = &mut [[(); usize::MAX]; 2][..]; + let _ = x.as_flattened_mut(); +} + +#[test] +fn test_get_many_mut_normal_2() { + let mut v = vec![1, 2, 3, 4, 5]; + let [a, b] = v.get_many_mut([3, 0]).unwrap(); + *a += 10; + *b += 100; + assert_eq!(v, vec![101, 2, 3, 14, 5]); + + let [a, b] = v.get_many_mut([0..=1, 2..=2]).unwrap(); + assert_eq!(a, &mut [101, 2][..]); + assert_eq!(b, &mut [3][..]); + a[0] += 10; + a[1] += 20; + b[0] += 100; + assert_eq!(v, vec![111, 22, 103, 14, 5]); +} + +#[test] +fn test_get_many_mut_normal_3() { + let mut v = vec![1, 2, 3, 4, 5]; + let [a, b, c] = v.get_many_mut([0, 4, 2]).unwrap(); + *a += 10; + *b += 100; + *c += 1000; + assert_eq!(v, vec![11, 2, 1003, 4, 105]); + + let [a, b, c] = v.get_many_mut([0..1, 4..5, 1..4]).unwrap(); + assert_eq!(a, &mut [11][..]); + assert_eq!(b, &mut [105][..]); + assert_eq!(c, &mut [2, 1003, 4][..]); + a[0] += 10; + b[0] += 100; + c[0] += 1000; + assert_eq!(v, vec![21, 1002, 1003, 4, 205]); +} + +#[test] +fn test_get_many_mut_empty() { + let mut v = vec![1, 2, 3, 4, 5]; + let [] = v.get_many_mut::([]).unwrap(); + let [] = v.get_many_mut::, 0>([]).unwrap(); + let [] = v.get_many_mut::, 0>([]).unwrap(); + assert_eq!(v, vec![1, 2, 3, 4, 5]); +} + +#[test] +fn test_get_many_mut_single_first() { + let mut v = vec![1, 2, 3, 4, 5]; + let [a] = v.get_many_mut([0]).unwrap(); + *a += 10; + assert_eq!(v, vec![11, 2, 3, 4, 5]); +} + +#[test] +fn test_get_many_mut_single_last() { + let mut v = vec![1, 2, 3, 4, 5]; + let [a] = v.get_many_mut([4]).unwrap(); + *a += 10; + assert_eq!(v, vec![1, 2, 3, 4, 15]); +} + +#[test] +fn test_get_many_mut_oob_nonempty() { + let mut v = vec![1, 2, 3, 4, 5]; + assert!(v.get_many_mut([5]).is_err()); +} + +#[test] +fn test_get_many_mut_oob_empty() { + let mut v: Vec = vec![]; + assert!(v.get_many_mut([0]).is_err()); +} + +#[test] +fn test_get_many_mut_duplicate() { + let mut v = vec![1, 2, 3, 4, 5]; + assert!(v.get_many_mut([1, 3, 3, 4]).is_err()); +} + +#[test] +fn test_get_many_mut_range_oob() { + let mut v = vec![1, 2, 3, 4, 5]; + assert!(v.get_many_mut([0..6]).is_err()); + assert!(v.get_many_mut([5..6]).is_err()); + assert!(v.get_many_mut([6..6]).is_err()); + assert!(v.get_many_mut([0..=5]).is_err()); + assert!(v.get_many_mut([0..=6]).is_err()); + assert!(v.get_many_mut([5..=5]).is_err()); +} + +#[test] +fn test_get_many_mut_range_overlapping() { + let mut v = vec![1, 2, 3, 4, 5]; + assert!(v.get_many_mut([0..1, 0..2]).is_err()); + assert!(v.get_many_mut([0..1, 1..2, 0..1]).is_err()); + assert!(v.get_many_mut([0..3, 1..1]).is_err()); + assert!(v.get_many_mut([0..3, 1..2]).is_err()); + assert!(v.get_many_mut([0..=0, 2..=2, 0..=1]).is_err()); + assert!(v.get_many_mut([0..=4, 0..=0]).is_err()); + assert!(v.get_many_mut([4..=4, 0..=0, 3..=4]).is_err()); +} + +#[test] +fn test_get_many_mut_range_empty_at_edge() { + let mut v = vec![1, 2, 3, 4, 5]; + assert_eq!( + v.get_many_mut([0..0, 0..5, 5..5]), + Ok([&mut [][..], &mut [1, 2, 3, 4, 5], &mut []]), + ); + assert_eq!( + v.get_many_mut([0..0, 0..1, 1..1, 1..2, 2..2, 2..3, 3..3, 3..4, 4..4, 4..5, 5..5]), + Ok([ + &mut [][..], + &mut [1], + &mut [], + &mut [2], + &mut [], + &mut [3], + &mut [], + &mut [4], + &mut [], + &mut [5], + &mut [], + ]), + ); +} + +#[test] +fn test_slice_from_raw_parts_in_const() { + static FANCY: i32 = 4; + static FANCY_SLICE: &[i32] = unsafe { std::slice::from_raw_parts(&FANCY, 1) }; + assert_eq!(FANCY_SLICE.as_ptr(), std::ptr::addr_of!(FANCY)); + assert_eq!(FANCY_SLICE.len(), 1); + + const EMPTY_SLICE: &[i32] = + unsafe { std::slice::from_raw_parts(std::ptr::without_provenance(123456), 0) }; + assert_eq!(EMPTY_SLICE.as_ptr().addr(), 123456); + assert_eq!(EMPTY_SLICE.len(), 0); +} diff --git a/library/coretests/tests/str.rs b/library/coretests/tests/str.rs new file mode 100644 index 00000000000..f5066343af2 --- /dev/null +++ b/library/coretests/tests/str.rs @@ -0,0 +1 @@ +// All `str` tests live in library/alloc/tests/str.rs diff --git a/library/coretests/tests/str_lossy.rs b/library/coretests/tests/str_lossy.rs new file mode 100644 index 00000000000..6e70ea3e285 --- /dev/null +++ b/library/coretests/tests/str_lossy.rs @@ -0,0 +1,83 @@ +#[test] +fn chunks() { + macro_rules! assert_chunks { + ( $string:expr, $(($valid:expr, $invalid:expr)),* $(,)? ) => {{ + let mut iter = $string.utf8_chunks(); + $( + let chunk = iter.next().expect("missing chunk"); + assert_eq!($valid, chunk.valid()); + assert_eq!($invalid, chunk.invalid()); + )* + assert_eq!(None, iter.next()); + }}; + } + + assert_chunks!(b"hello", ("hello", b"")); + assert_chunks!("ศไทย中华Việt Nam".as_bytes(), ("ศไทย中华Việt Nam", b"")); + assert_chunks!( + b"Hello\xC2 There\xFF Goodbye", + ("Hello", b"\xC2"), + (" There", b"\xFF"), + (" Goodbye", b""), + ); + assert_chunks!( + b"Hello\xC0\x80 There\xE6\x83 Goodbye", + ("Hello", b"\xC0"), + ("", b"\x80"), + (" There", b"\xE6\x83"), + (" Goodbye", b""), + ); + assert_chunks!( + b"\xF5foo\xF5\x80bar", + ("", b"\xF5"), + ("foo", b"\xF5"), + ("", b"\x80"), + ("bar", b""), + ); + assert_chunks!( + b"\xF1foo\xF1\x80bar\xF1\x80\x80baz", + ("", b"\xF1"), + ("foo", b"\xF1\x80"), + ("bar", b"\xF1\x80\x80"), + ("baz", b""), + ); + assert_chunks!( + b"\xF4foo\xF4\x80bar\xF4\xBFbaz", + ("", b"\xF4"), + ("foo", b"\xF4\x80"), + ("bar", b"\xF4"), + ("", b"\xBF"), + ("baz", b""), + ); + assert_chunks!( + b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar", + ("", b"\xF0"), + ("", b"\x80"), + ("", b"\x80"), + ("", b"\x80"), + ("foo\u{10000}bar", b""), + ); + + // surrogates + assert_chunks!( + b"\xED\xA0\x80foo\xED\xBF\xBFbar", + ("", b"\xED"), + ("", b"\xA0"), + ("", b"\x80"), + ("foo", b"\xED"), + ("", b"\xBF"), + ("", b"\xBF"), + ("bar", b""), + ); +} + +#[test] +fn debug() { + assert_eq!( + "\"Hello\\xC0\\x80 There\\xE6\\x83 Goodbye\\u{10d4ea}\"", + &format!( + "{:?}", + b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa".utf8_chunks().debug(), + ), + ); +} diff --git a/library/coretests/tests/task.rs b/library/coretests/tests/task.rs new file mode 100644 index 00000000000..163b34c9648 --- /dev/null +++ b/library/coretests/tests/task.rs @@ -0,0 +1,25 @@ +use core::task::{Poll, RawWaker, RawWakerVTable, Waker}; + +#[test] +fn poll_const() { + // test that the methods of `Poll` are usable in a const context + + const POLL: Poll = Poll::Pending; + + const IS_READY: bool = POLL.is_ready(); + assert!(!IS_READY); + + const IS_PENDING: bool = POLL.is_pending(); + assert!(IS_PENDING); +} + +#[test] +fn waker_const() { + const VOID_TABLE: RawWakerVTable = RawWakerVTable::new(|_| VOID_WAKER, |_| {}, |_| {}, |_| {}); + + const VOID_WAKER: RawWaker = RawWaker::new(&(), &VOID_TABLE); + + static WAKER: Waker = unsafe { Waker::from_raw(VOID_WAKER) }; + + WAKER.wake_by_ref(); +} diff --git a/library/coretests/tests/time.rs b/library/coretests/tests/time.rs new file mode 100644 index 00000000000..fe7bb11c675 --- /dev/null +++ b/library/coretests/tests/time.rs @@ -0,0 +1,564 @@ +use core::time::Duration; + +#[test] +fn creation() { + assert_ne!(Duration::from_secs(1), Duration::from_secs(0)); + assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), Duration::from_secs(3)); + assert_eq!( + Duration::from_millis(10) + Duration::from_secs(4), + Duration::new(4, 10 * 1_000_000) + ); + assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); +} + +#[test] +#[should_panic] +fn new_overflow() { + let _ = Duration::new(u64::MAX, 1_000_000_000); +} + +#[test] +#[should_panic] +fn from_mins_overflow() { + let overflow = u64::MAX / 60 + 1; + let _ = Duration::from_mins(overflow); +} + +#[test] +#[should_panic] +fn from_hours_overflow() { + let overflow = u64::MAX / (60 * 60) + 1; + let _ = Duration::from_hours(overflow); +} + +#[test] +#[should_panic] +fn from_days_overflow() { + let overflow = u64::MAX / (24 * 60 * 60) + 1; + let _ = Duration::from_days(overflow); +} + +#[test] +#[should_panic] +fn from_weeks_overflow() { + let overflow = u64::MAX / (7 * 24 * 60 * 60) + 1; + let _ = Duration::from_weeks(overflow); +} + +#[test] +fn constructors() { + assert_eq!(Duration::from_weeks(1), Duration::from_secs(7 * 24 * 60 * 60)); + assert_eq!(Duration::from_weeks(0), Duration::ZERO); + + assert_eq!(Duration::from_days(1), Duration::from_secs(86_400)); + assert_eq!(Duration::from_days(0), Duration::ZERO); + + assert_eq!(Duration::from_hours(1), Duration::from_secs(3_600)); + assert_eq!(Duration::from_hours(0), Duration::ZERO); + + assert_eq!(Duration::from_mins(1), Duration::from_secs(60)); + assert_eq!(Duration::from_mins(0), Duration::ZERO); +} + +#[test] +fn secs() { + assert_eq!(Duration::new(0, 0).as_secs(), 0); + assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0); + assert_eq!(Duration::new(0, 1_050_000_001).as_secs(), 1); + assert_eq!(Duration::from_secs(1).as_secs(), 1); + assert_eq!(Duration::from_millis(999).as_secs(), 0); + assert_eq!(Duration::from_millis(1001).as_secs(), 1); + assert_eq!(Duration::from_micros(999_999).as_secs(), 0); + assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1); + assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0); + assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1); +} + +#[test] +fn millis() { + assert_eq!(Duration::new(0, 0).subsec_millis(), 0); + assert_eq!(Duration::new(0, 500_000_005).subsec_millis(), 500); + assert_eq!(Duration::new(0, 1_050_000_001).subsec_millis(), 50); + assert_eq!(Duration::from_secs(1).subsec_millis(), 0); + assert_eq!(Duration::from_millis(999).subsec_millis(), 999); + assert_eq!(Duration::from_millis(1001).subsec_millis(), 1); + assert_eq!(Duration::from_micros(999_999).subsec_millis(), 999); + assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1); + assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999); + assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1); +} + +#[test] +fn micros() { + assert_eq!(Duration::new(0, 0).subsec_micros(), 0); + assert_eq!(Duration::new(0, 500_000_005).subsec_micros(), 500_000); + assert_eq!(Duration::new(0, 1_050_000_001).subsec_micros(), 50_000); + assert_eq!(Duration::from_secs(1).subsec_micros(), 0); + assert_eq!(Duration::from_millis(999).subsec_micros(), 999_000); + assert_eq!(Duration::from_millis(1001).subsec_micros(), 1_000); + assert_eq!(Duration::from_micros(999_999).subsec_micros(), 999_999); + assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1); + assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999); + assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1); +} + +#[test] +fn nanos() { + assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); + assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); + assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); + assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); + assert_eq!(Duration::from_millis(999).subsec_nanos(), 999_000_000); + assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1_000_000); + assert_eq!(Duration::from_micros(999_999).subsec_nanos(), 999_999_000); + assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000); + assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999); + assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1); +} + +#[test] +fn abs_diff() { + assert_eq!(Duration::new(2, 0).abs_diff(Duration::new(1, 0)), Duration::new(1, 0)); + assert_eq!(Duration::new(1, 0).abs_diff(Duration::new(2, 0)), Duration::new(1, 0)); + assert_eq!(Duration::new(1, 0).abs_diff(Duration::new(1, 0)), Duration::new(0, 0)); + assert_eq!(Duration::new(1, 1).abs_diff(Duration::new(0, 2)), Duration::new(0, 999_999_999)); + assert_eq!(Duration::new(1, 1).abs_diff(Duration::new(2, 1)), Duration::new(1, 0)); + assert_eq!(Duration::MAX.abs_diff(Duration::MAX), Duration::ZERO); + assert_eq!(Duration::ZERO.abs_diff(Duration::ZERO), Duration::ZERO); + assert_eq!(Duration::MAX.abs_diff(Duration::ZERO), Duration::MAX); + assert_eq!(Duration::ZERO.abs_diff(Duration::MAX), Duration::MAX); +} + +#[test] +fn add() { + assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), Duration::new(1, 1)); +} + +#[test] +fn checked_add() { + assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); + assert_eq!( + Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), + Some(Duration::new(1, 1)) + ); + assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None); +} + +#[test] +fn saturating_add() { + assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); + assert_eq!( + Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)), + Duration::new(1, 1) + ); + assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); +} + +#[test] +fn sub() { + assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), Duration::new(0, 1)); + assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), Duration::new(0, 999_999_999)); +} + +#[test] +fn checked_sub() { + assert_eq!(Duration::NANOSECOND.checked_sub(Duration::ZERO), Some(Duration::NANOSECOND)); + assert_eq!( + Duration::SECOND.checked_sub(Duration::NANOSECOND), + Some(Duration::new(0, 999_999_999)) + ); + assert_eq!(Duration::ZERO.checked_sub(Duration::NANOSECOND), None); + assert_eq!(Duration::ZERO.checked_sub(Duration::SECOND), None); +} + +#[test] +fn saturating_sub() { + assert_eq!(Duration::NANOSECOND.saturating_sub(Duration::ZERO), Duration::NANOSECOND); + assert_eq!( + Duration::SECOND.saturating_sub(Duration::NANOSECOND), + Duration::new(0, 999_999_999) + ); + assert_eq!(Duration::ZERO.saturating_sub(Duration::NANOSECOND), Duration::ZERO); + assert_eq!(Duration::ZERO.saturating_sub(Duration::SECOND), Duration::ZERO); +} + +#[test] +#[should_panic] +fn sub_bad1() { + let _ = Duration::new(0, 0) - Duration::new(0, 1); +} + +#[test] +#[should_panic] +fn sub_bad2() { + let _ = Duration::new(0, 0) - Duration::new(1, 0); +} + +#[test] +fn mul() { + assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001) * 4000, Duration::new(2000, 4000)); +} + +#[test] +fn checked_mul() { + assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); + assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), Some(Duration::new(2000, 4000))); + assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None); +} + +#[test] +fn saturating_mul() { + assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000)); + assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); +} + +#[test] +fn div() { + assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); + assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); + assert_eq!(Duration::new(1, 1) / 7, Duration::new(0, 142_857_143)); + assert_eq!(Duration::new(99, 999_999_000) / 100, Duration::new(0, 999_999_990)); +} + +#[test] +fn div_duration_f32() { + assert_eq!(Duration::ZERO.div_duration_f32(Duration::MAX), 0.0); + assert_eq!(Duration::MAX.div_duration_f32(Duration::ZERO), f32::INFINITY); + assert_eq!((Duration::SECOND * 2).div_duration_f32(Duration::SECOND), 2.0); + assert!(Duration::ZERO.div_duration_f32(Duration::ZERO).is_nan()); + // These tests demonstrate it doesn't panic with extreme values. + // Accuracy of the computed value is not a huge concern, we know floats don't work well + // at these extremes. + assert!((Duration::MAX).div_duration_f32(Duration::NANOSECOND) > 10.0f32.powf(28.0)); + assert!((Duration::NANOSECOND).div_duration_f32(Duration::MAX) < 0.1); +} + +#[test] +fn div_duration_f64() { + assert_eq!(Duration::ZERO.div_duration_f64(Duration::MAX), 0.0); + assert_eq!(Duration::MAX.div_duration_f64(Duration::ZERO), f64::INFINITY); + assert_eq!((Duration::SECOND * 2).div_duration_f64(Duration::SECOND), 2.0); + assert!(Duration::ZERO.div_duration_f64(Duration::ZERO).is_nan()); + // These tests demonstrate it doesn't panic with extreme values. + // Accuracy of the computed value is not a huge concern, we know floats don't work well + // at these extremes. + assert!((Duration::MAX).div_duration_f64(Duration::NANOSECOND) > 10.0f64.powf(28.0)); + assert!((Duration::NANOSECOND).div_duration_f64(Duration::MAX) < 0.1); +} + +#[test] +fn checked_div() { + assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + assert_eq!(Duration::new(2, 0).checked_div(0), None); +} + +#[test] +fn correct_sum() { + let durations = [ + Duration::new(1, 999_999_999), + Duration::new(2, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(5, 0), + ]; + let sum = durations.iter().sum::(); + assert_eq!(sum, Duration::new(1 + 2 + 5 + 4, 1_000_000_000 - 5)); +} + +#[test] +fn debug_formatting_extreme_values() { + assert_eq!( + format!("{:?}", Duration::new(u64::MAX, 123_456_789)), + "18446744073709551615.123456789s" + ); + assert_eq!(format!("{:.0?}", Duration::MAX), "18446744073709551616s"); + assert_eq!(format!("{:.0?}", Duration::new(u64::MAX, 500_000_000)), "18446744073709551616s"); + assert_eq!(format!("{:.0?}", Duration::new(u64::MAX, 499_999_999)), "18446744073709551615s"); + assert_eq!( + format!("{:.3?}", Duration::new(u64::MAX, 999_500_000)), + "18446744073709551616.000s" + ); + assert_eq!( + format!("{:.3?}", Duration::new(u64::MAX, 999_499_999)), + "18446744073709551615.999s" + ); + assert_eq!( + format!("{:.8?}", Duration::new(u64::MAX, 999_999_995)), + "18446744073709551616.00000000s" + ); + assert_eq!( + format!("{:.8?}", Duration::new(u64::MAX, 999_999_994)), + "18446744073709551615.99999999s" + ); + assert_eq!(format!("{:21.0?}", Duration::MAX), "18446744073709551616s"); + assert_eq!(format!("{:22.0?}", Duration::MAX), "18446744073709551616s "); + assert_eq!(format!("{:24.0?}", Duration::MAX), "18446744073709551616s "); +} + +#[test] +fn debug_formatting_secs() { + assert_eq!(format!("{:?}", Duration::new(7, 000_000_000)), "7s"); + assert_eq!(format!("{:?}", Duration::new(7, 100_000_000)), "7.1s"); + assert_eq!(format!("{:?}", Duration::new(7, 000_010_000)), "7.00001s"); + assert_eq!(format!("{:?}", Duration::new(7, 000_000_001)), "7.000000001s"); + assert_eq!(format!("{:?}", Duration::new(7, 123_456_789)), "7.123456789s"); + + assert_eq!(format!("{:?}", Duration::new(88, 000_000_000)), "88s"); + assert_eq!(format!("{:?}", Duration::new(88, 100_000_000)), "88.1s"); + assert_eq!(format!("{:?}", Duration::new(88, 000_010_000)), "88.00001s"); + assert_eq!(format!("{:?}", Duration::new(88, 000_000_001)), "88.000000001s"); + assert_eq!(format!("{:?}", Duration::new(88, 123_456_789)), "88.123456789s"); + + assert_eq!(format!("{:?}", Duration::new(999, 000_000_000)), "999s"); + assert_eq!(format!("{:?}", Duration::new(999, 100_000_000)), "999.1s"); + assert_eq!(format!("{:?}", Duration::new(999, 000_010_000)), "999.00001s"); + assert_eq!(format!("{:?}", Duration::new(999, 000_000_001)), "999.000000001s"); + assert_eq!(format!("{:?}", Duration::new(999, 123_456_789)), "999.123456789s"); +} + +#[test] +fn debug_formatting_millis() { + assert_eq!(format!("{:?}", Duration::new(0, 7_000_000)), "7ms"); + assert_eq!(format!("{:?}", Duration::new(0, 7_100_000)), "7.1ms"); + assert_eq!(format!("{:?}", Duration::new(0, 7_000_001)), "7.000001ms"); + assert_eq!(format!("{:?}", Duration::new(0, 7_123_456)), "7.123456ms"); + + assert_eq!(format!("{:?}", Duration::new(0, 88_000_000)), "88ms"); + assert_eq!(format!("{:?}", Duration::new(0, 88_100_000)), "88.1ms"); + assert_eq!(format!("{:?}", Duration::new(0, 88_000_001)), "88.000001ms"); + assert_eq!(format!("{:?}", Duration::new(0, 88_123_456)), "88.123456ms"); + + assert_eq!(format!("{:?}", Duration::new(0, 999_000_000)), "999ms"); + assert_eq!(format!("{:?}", Duration::new(0, 999_100_000)), "999.1ms"); + assert_eq!(format!("{:?}", Duration::new(0, 999_000_001)), "999.000001ms"); + assert_eq!(format!("{:?}", Duration::new(0, 999_123_456)), "999.123456ms"); +} + +#[test] +fn debug_formatting_micros() { + assert_eq!(format!("{:?}", Duration::new(0, 7_000)), "7µs"); + assert_eq!(format!("{:?}", Duration::new(0, 7_100)), "7.1µs"); + assert_eq!(format!("{:?}", Duration::new(0, 7_001)), "7.001µs"); + assert_eq!(format!("{:?}", Duration::new(0, 7_123)), "7.123µs"); + + assert_eq!(format!("{:?}", Duration::new(0, 88_000)), "88µs"); + assert_eq!(format!("{:?}", Duration::new(0, 88_100)), "88.1µs"); + assert_eq!(format!("{:?}", Duration::new(0, 88_001)), "88.001µs"); + assert_eq!(format!("{:?}", Duration::new(0, 88_123)), "88.123µs"); + + assert_eq!(format!("{:?}", Duration::new(0, 999_000)), "999µs"); + assert_eq!(format!("{:?}", Duration::new(0, 999_100)), "999.1µs"); + assert_eq!(format!("{:?}", Duration::new(0, 999_001)), "999.001µs"); + assert_eq!(format!("{:?}", Duration::new(0, 999_123)), "999.123µs"); +} + +#[test] +fn debug_formatting_nanos() { + assert_eq!(format!("{:?}", Duration::new(0, 0)), "0ns"); + assert_eq!(format!("{:?}", Duration::new(0, 1)), "1ns"); + assert_eq!(format!("{:?}", Duration::new(0, 88)), "88ns"); + assert_eq!(format!("{:?}", Duration::new(0, 999)), "999ns"); +} + +#[test] +fn debug_formatting_precision_zero() { + assert_eq!(format!("{:.0?}", Duration::new(0, 0)), "0ns"); + assert_eq!(format!("{:.0?}", Duration::new(0, 123)), "123ns"); + + assert_eq!(format!("{:.0?}", Duration::new(0, 1_001)), "1µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_499)), "1µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_500)), "2µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_999)), "2µs"); + + assert_eq!(format!("{:.0?}", Duration::new(0, 1_000_001)), "1ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_499_999)), "1ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_500_000)), "2ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_999_999)), "2ms"); + + assert_eq!(format!("{:.0?}", Duration::new(1, 000_000_001)), "1s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 499_999_999)), "1s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 500_000_000)), "2s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 999_999_999)), "2s"); +} + +#[test] +fn debug_formatting_precision_two() { + assert_eq!(format!("{:.2?}", Duration::new(0, 0)), "0.00ns"); + assert_eq!(format!("{:.2?}", Duration::new(0, 123)), "123.00ns"); + + assert_eq!(format!("{:.2?}", Duration::new(0, 1_000)), "1.00µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_001)), "7.00µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_100)), "7.10µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_109)), "7.11µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_199)), "7.20µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 1_999)), "2.00µs"); + + assert_eq!(format!("{:.2?}", Duration::new(0, 1_000_000)), "1.00ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 3_001_000)), "3.00ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 3_100_000)), "3.10ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 1_999_999)), "2.00ms"); + + assert_eq!(format!("{:.2?}", Duration::new(1, 000_000_000)), "1.00s"); + assert_eq!(format!("{:.2?}", Duration::new(4, 001_000_000)), "4.00s"); + assert_eq!(format!("{:.2?}", Duration::new(2, 100_000_000)), "2.10s"); + assert_eq!(format!("{:.2?}", Duration::new(2, 104_990_000)), "2.10s"); + assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.11s"); + assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s"); +} + +#[test] +fn debug_formatting_padding() { + assert_eq!("0ns ", format!("{:<9?}", Duration::new(0, 0))); + assert_eq!(" 0ns", format!("{:>9?}", Duration::new(0, 0))); + assert_eq!(" 0ns ", format!("{:^9?}", Duration::new(0, 0))); + assert_eq!("123ns ", format!("{:<9.0?}", Duration::new(0, 123))); + assert_eq!(" 123ns", format!("{:>9.0?}", Duration::new(0, 123))); + assert_eq!(" 123ns ", format!("{:^9.0?}", Duration::new(0, 123))); + assert_eq!("123.0ns ", format!("{:<9.1?}", Duration::new(0, 123))); + assert_eq!(" 123.0ns", format!("{:>9.1?}", Duration::new(0, 123))); + assert_eq!(" 123.0ns ", format!("{:^9.1?}", Duration::new(0, 123))); + assert_eq!("7.1µs ", format!("{:<9?}", Duration::new(0, 7_100))); + assert_eq!(" 7.1µs", format!("{:>9?}", Duration::new(0, 7_100))); + assert_eq!(" 7.1µs ", format!("{:^9?}", Duration::new(0, 7_100))); + assert_eq!("999.123456ms", format!("{:<9?}", Duration::new(0, 999_123_456))); + assert_eq!("999.123456ms", format!("{:>9?}", Duration::new(0, 999_123_456))); + assert_eq!("999.123456ms", format!("{:^9?}", Duration::new(0, 999_123_456))); + assert_eq!("5s ", format!("{:<9?}", Duration::new(5, 0))); + assert_eq!(" 5s", format!("{:>9?}", Duration::new(5, 0))); + assert_eq!(" 5s ", format!("{:^9?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:<9.12?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:>9.12?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:^9.12?}", Duration::new(5, 0))); + + // default alignment is left: + assert_eq!("5s ", format!("{:9?}", Duration::new(5, 0))); +} + +#[test] +fn debug_formatting_precision_high() { + assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs"); + + assert_eq!(format!("{:.9?}", Duration::new(1, 000_000_000)), "1.000000000s"); + assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s"); + assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s"); +} + +#[test] +fn duration_const() { + // test that the methods of `Duration` are usable in a const context + + const DURATION: Duration = Duration::new(0, 123_456_789); + + const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis(); + assert_eq!(SUB_SEC_MILLIS, 123); + + const SUB_SEC_MICROS: u32 = DURATION.subsec_micros(); + assert_eq!(SUB_SEC_MICROS, 123_456); + + const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos(); + assert_eq!(SUB_SEC_NANOS, 123_456_789); + + const IS_ZERO: bool = Duration::ZERO.is_zero(); + assert!(IS_ZERO); + + const SECONDS: u64 = Duration::SECOND.as_secs(); + assert_eq!(SECONDS, 1); + + const FROM_SECONDS: Duration = Duration::from_secs(1); + assert_eq!(FROM_SECONDS, Duration::SECOND); + + const SECONDS_F32: f32 = Duration::SECOND.as_secs_f32(); + assert_eq!(SECONDS_F32, 1.0); + + // FIXME(#110395) + // const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0); + // assert_eq!(FROM_SECONDS_F32, Duration::SECOND); + + const SECONDS_F64: f64 = Duration::SECOND.as_secs_f64(); + assert_eq!(SECONDS_F64, 1.0); + + // FIXME(#110395) + // const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0); + // assert_eq!(FROM_SECONDS_F64, Duration::SECOND); + + const MILLIS: u128 = Duration::SECOND.as_millis(); + assert_eq!(MILLIS, 1_000); + + const FROM_MILLIS: Duration = Duration::from_millis(1_000); + assert_eq!(FROM_MILLIS, Duration::SECOND); + + const MICROS: u128 = Duration::SECOND.as_micros(); + assert_eq!(MICROS, 1_000_000); + + const FROM_MICROS: Duration = Duration::from_micros(1_000_000); + assert_eq!(FROM_MICROS, Duration::SECOND); + + const NANOS: u128 = Duration::SECOND.as_nanos(); + assert_eq!(NANOS, 1_000_000_000); + + const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000); + assert_eq!(FROM_NANOS, Duration::SECOND); + + const MAX: Duration = Duration::new(u64::MAX, 999_999_999); + + const CHECKED_ADD: Option = MAX.checked_add(Duration::SECOND); + assert_eq!(CHECKED_ADD, None); + + const CHECKED_SUB: Option = Duration::ZERO.checked_sub(Duration::SECOND); + assert_eq!(CHECKED_SUB, None); + + const CHECKED_MUL: Option = Duration::SECOND.checked_mul(1); + assert_eq!(CHECKED_MUL, Some(Duration::SECOND)); + + /* FIXME(#110395) + const MUL_F32: Duration = Duration::SECOND.mul_f32(1.0); + assert_eq!(MUL_F32, Duration::SECOND); + + const MUL_F64: Duration = Duration::SECOND.mul_f64(1.0); + assert_eq!(MUL_F64, Duration::SECOND); + + const CHECKED_DIV: Option = Duration::SECOND.checked_div(1); + assert_eq!(CHECKED_DIV, Some(Duration::SECOND)); + + const DIV_F32: Duration = Duration::SECOND.div_f32(1.0); + assert_eq!(DIV_F32, Duration::SECOND); + + const DIV_F64: Duration = Duration::SECOND.div_f64(1.0); + assert_eq!(DIV_F64, Duration::SECOND); + */ + + const DIV_DURATION_F32: f32 = Duration::SECOND.div_duration_f32(Duration::SECOND); + assert_eq!(DIV_DURATION_F32, 1.0); + + const DIV_DURATION_F64: f64 = Duration::SECOND.div_duration_f64(Duration::SECOND); + assert_eq!(DIV_DURATION_F64, 1.0); + + const SATURATING_ADD: Duration = MAX.saturating_add(Duration::SECOND); + assert_eq!(SATURATING_ADD, MAX); + + const SATURATING_SUB: Duration = Duration::ZERO.saturating_sub(Duration::SECOND); + assert_eq!(SATURATING_SUB, Duration::ZERO); + + const SATURATING_MUL: Duration = MAX.saturating_mul(2); + assert_eq!(SATURATING_MUL, MAX); +} + +#[test] +fn from_neg_zero() { + assert_eq!(Duration::try_from_secs_f32(-0.0), Ok(Duration::ZERO)); + assert_eq!(Duration::try_from_secs_f64(-0.0), Ok(Duration::ZERO)); + assert_eq!(Duration::from_secs_f32(-0.0), Duration::ZERO); + assert_eq!(Duration::from_secs_f64(-0.0), Duration::ZERO); +} diff --git a/library/coretests/tests/tuple.rs b/library/coretests/tests/tuple.rs new file mode 100644 index 00000000000..ea1e281425c --- /dev/null +++ b/library/coretests/tests/tuple.rs @@ -0,0 +1,61 @@ +use std::cmp::Ordering::{Equal, Greater, Less}; + +#[test] +fn test_clone() { + let a = (1, "2"); + let b = a.clone(); + assert_eq!(a, b); +} + +#[test] +fn test_partial_eq() { + let (small, big) = ((1, 2, 3), (3, 2, 1)); + assert_eq!(small, small); + assert_eq!(big, big); + assert_ne!(small, big); + assert_ne!(big, small); +} + +#[test] +fn test_partial_ord() { + let (small, big) = ((1, 2, 3), (3, 2, 1)); + + assert!(small < big); + assert!(!(small < small)); + assert!(!(big < small)); + assert!(!(big < big)); + + assert!(small <= small); + assert!(big <= big); + + assert!(big > small); + assert!(small >= small); + assert!(big >= small); + assert!(big >= big); + + assert!(!((1.0f64, 2.0f64) < (f64::NAN, 3.0))); + assert!(!((1.0f64, 2.0f64) <= (f64::NAN, 3.0))); + assert!(!((1.0f64, 2.0f64) > (f64::NAN, 3.0))); + assert!(!((1.0f64, 2.0f64) >= (f64::NAN, 3.0))); + assert!(((1.0f64, 2.0f64) < (2.0, f64::NAN))); + assert!(!((2.0f64, 2.0f64) < (2.0, f64::NAN))); +} + +#[test] +fn test_ord() { + let (small, big) = ((1, 2, 3), (3, 2, 1)); + assert_eq!(small.cmp(&small), Equal); + assert_eq!(big.cmp(&big), Equal); + assert_eq!(small.cmp(&big), Less); + assert_eq!(big.cmp(&small), Greater); +} + +#[test] +fn test_show() { + let s = format!("{:?}", (1,)); + assert_eq!(s, "(1,)"); + let s = format!("{:?}", (1, true)); + assert_eq!(s, "(1, true)"); + let s = format!("{:?}", (1, "hi", true)); + assert_eq!(s, "(1, \"hi\", true)"); +} diff --git a/library/coretests/tests/unicode.rs b/library/coretests/tests/unicode.rs new file mode 100644 index 00000000000..bbace0ef66c --- /dev/null +++ b/library/coretests/tests/unicode.rs @@ -0,0 +1,5 @@ +#[test] +pub fn version() { + let (major, _minor, _update) = core::char::UNICODE_VERSION; + assert!(major >= 10); +} diff --git a/library/coretests/tests/waker.rs b/library/coretests/tests/waker.rs new file mode 100644 index 00000000000..4889b8959ec --- /dev/null +++ b/library/coretests/tests/waker.rs @@ -0,0 +1,51 @@ +use std::ptr; +use std::task::{RawWaker, RawWakerVTable, Waker}; + +#[test] +fn test_waker_getters() { + let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE); + let waker = unsafe { Waker::from_raw(raw_waker) }; + assert_eq!(waker.data() as usize, 42); + assert!(ptr::eq(waker.vtable(), &WAKER_VTABLE)); + + let waker2 = waker.clone(); + assert_eq!(waker2.data() as usize, 43); + assert!(ptr::eq(waker2.vtable(), &WAKER_VTABLE)); +} + +static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( + |data| RawWaker::new(ptr::without_provenance_mut(data as usize + 1), &WAKER_VTABLE), + |_| {}, + |_| {}, + |_| {}, +); + +// https://github.com/rust-lang/rust/issues/102012#issuecomment-1915282956 +mod nop_waker { + use core::future::{Future, ready}; + use core::pin::Pin; + use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; + + const NOP_RAWWAKER: RawWaker = { + fn nop(_: *const ()) {} + const VTAB: RawWakerVTable = RawWakerVTable::new(|_| NOP_RAWWAKER, nop, nop, nop); + RawWaker::new(&() as *const (), &VTAB) + }; + + const NOP_WAKER: &Waker = &unsafe { Waker::from_raw(NOP_RAWWAKER) }; + + const NOP_CONTEXT: Context<'static> = Context::from_waker(NOP_WAKER); + + fn poll_once(f: &mut F) -> Poll + where + F: Future + ?Sized + Unpin, + { + let mut cx = NOP_CONTEXT; + Pin::new(f).as_mut().poll(&mut cx) + } + + #[test] + fn test_const_waker() { + assert_eq!(poll_once(&mut ready(1)), Poll::Ready(1)); + } +} diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 275c0e803cb..7e6a39a236e 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -55,14 +55,14 @@ check-aux: $(BOOTSTRAP_ARGS) # Run standard library tests in Miri. $(Q)$(BOOTSTRAP) miri --stage 2 \ - library/core \ + library/coretests \ library/alloc \ $(BOOTSTRAP_ARGS) \ --no-doc # Some doctests use file system operations to demonstrate dealing with `Result`. $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ - library/core \ + library/coretests \ library/alloc \ $(BOOTSTRAP_ARGS) \ --doc diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index d8d862caf6a..f4a86e26396 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -45,7 +45,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("sysroot").path("library") + run.crate_or_deps("sysroot").crate_or_deps("coretests").path("library") } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 99b033db115..5e250d18ce6 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2658,7 +2658,7 @@ impl Step for Crate { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("sysroot") + run.crate_or_deps("sysroot").crate_or_deps("coretests") } fn make_run(run: RunConfig<'_>) { -- cgit 1.4.1-3-g733a5 From 4febbd5c09332776bf1fe7e979f8651705c18b27 Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" <39484203+jieyouxu@users.noreply.github.com> Date: Sat, 25 Jan 2025 15:59:29 +0800 Subject: bootstrap: avoid glob imports in `main` binary --- src/bootstrap/src/bin/main.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 8ebd6b8aa54..90bbbf49a77 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -16,11 +16,7 @@ use bootstrap::{ }; use build_helper::ci::CiEnv; #[cfg(feature = "tracing")] -use tracing::*; -#[cfg(feature = "tracing")] -use tracing_subscriber::EnvFilter; -#[cfg(feature = "tracing")] -use tracing_subscriber::prelude::*; +use tracing::{instrument, trace}; #[cfg_attr(feature = "tracing", instrument(level = "trace", name = "main"))] fn main() { @@ -211,6 +207,9 @@ fn check_version(config: &Config) -> Option { // "tracing", instrument(..))]`. #[cfg(feature = "tracing")] fn setup_tracing() { + use tracing_subscriber::EnvFilter; + use tracing_subscriber::layer::SubscriberExt; + let filter = EnvFilter::from_env("BOOTSTRAP_TRACING"); let layer = tracing_tree::HierarchicalLayer::default() .with_writer(std::io::stderr) -- cgit 1.4.1-3-g733a5 From 761bda1e432a90892a91f483c857098287847d14 Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" <39484203+jieyouxu@users.noreply.github.com> Date: Sat, 25 Jan 2025 23:10:57 +0800 Subject: bootstrap: adjust tracing style --- src/bootstrap/src/bin/main.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 90bbbf49a77..9f51580d47c 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -211,15 +211,10 @@ fn setup_tracing() { use tracing_subscriber::layer::SubscriberExt; let filter = EnvFilter::from_env("BOOTSTRAP_TRACING"); - let layer = tracing_tree::HierarchicalLayer::default() - .with_writer(std::io::stderr) - .with_ansi(true) - .with_targets(true) - .with_bracketed_fields(true) - .with_indent_amount(2) - .with_indent_lines(true); - let subscriber = tracing_subscriber::registry().with(filter).with(layer); - - tracing::subscriber::set_global_default(subscriber).unwrap(); - trace!("tracing subscriber setup"); + // cf. . + let layer = tracing_tree::HierarchicalLayer::default().with_targets(true).with_indent_amount(2); + + let registry = tracing_subscriber::registry().with(filter).with(layer); + + tracing::subscriber::set_global_default(registry).unwrap(); } -- cgit 1.4.1-3-g733a5 From 71703bb7d9f19d477a1c88f7ce8d4c9ce0055837 Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" <39484203+jieyouxu@users.noreply.github.com> Date: Sun, 26 Jan 2025 16:06:00 +0800 Subject: bootstrap: adjust config file cascading fallback comment --- src/bootstrap/src/core/config/config.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 910550b0a7d..ec0ba69c62a 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1418,7 +1418,11 @@ impl Config { config.stage0_metadata = build_helper::stage0_parser::parse_stage0_file(); - // Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory. + // Find configuration file, with the following cascading fallback (first match wins): + // - `--config ` + // - `RUST_BOOTSTRAP_CONFIG` + // - `./config.toml` + // - `config.toml` in the root directory. let toml_path = flags .config .clone() -- cgit 1.4.1-3-g733a5 From 2e1a5320f5ba99e3c5b79752d7ab1b8cabdf4ca7 Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" <39484203+jieyouxu@users.noreply.github.com> Date: Sat, 25 Jan 2025 23:11:12 +0800 Subject: bootstrap: add more logging --- src/bootstrap/src/bin/main.rs | 8 ++++++- src/bootstrap/src/core/config/config.rs | 41 +++++++++++++++++++++++++++++++++ src/bootstrap/src/core/config/flags.rs | 6 +++++ src/bootstrap/src/lib.rs | 40 +++++++++++++++++++++++++++++++- 4 files changed, 93 insertions(+), 2 deletions(-) (limited to 'src/bootstrap') diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 9f51580d47c..5fcf7eda8df 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -16,7 +16,7 @@ use bootstrap::{ }; use build_helper::ci::CiEnv; #[cfg(feature = "tracing")] -use tracing::{instrument, trace}; +use tracing::{debug, instrument}; #[cfg_attr(feature = "tracing", instrument(level = "trace", name = "main"))] fn main() { @@ -29,7 +29,11 @@ fn main() { return; } + #[cfg(feature = "tracing")] + debug!("parsing flags"); let flags = Flags::parse(&args); + #[cfg(feature = "tracing")] + debug!("parsing config based on flags"); let config = Config::parse(flags); let mut build_lock; @@ -91,6 +95,8 @@ fn main() { let dump_bootstrap_shims = config.dump_bootstrap_shims; let out_dir = config.out.clone(); + #[cfg(feature = "tracing")] + debug!("creating new build based on config"); Build::new(config).build(); if suggest_setup { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index ec0ba69c62a..98490118f7d 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -18,6 +18,8 @@ use build_helper::exit; use build_helper::git::{GitConfig, get_closest_merge_commit, output_result}; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; +#[cfg(feature = "tracing")] +use tracing::{instrument, span}; use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::build_steps::llvm; @@ -1227,7 +1229,14 @@ define_config! { } impl Config { + #[cfg_attr( + feature = "tracing", + instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::default_opts") + )] pub fn default_opts() -> Config { + #[cfg(feature = "tracing")] + span!(target: "CONFIG_HANDLING", tracing::Level::TRACE, "constructing default config"); + Config { bypass_bootstrap_lock: false, llvm_optimize: true, @@ -1311,10 +1320,23 @@ impl Config { }) } + #[cfg_attr( + feature = "tracing", + instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::parse", skip_all) + )] pub fn parse(flags: Flags) -> Config { Self::parse_inner(flags, Self::get_toml) } + #[cfg_attr( + feature = "tracing", + instrument( + target = "CONFIG_HANDLING", + level = "trace", + name = "Config::parse_inner", + skip_all + ) + )] pub(crate) fn parse_inner( mut flags: Flags, get_toml: impl Fn(&Path) -> Result, @@ -1323,6 +1345,17 @@ impl Config { // Set flags. config.paths = std::mem::take(&mut flags.paths); + + #[cfg(feature = "tracing")] + span!( + target: "CONFIG_HANDLING", + tracing::Level::TRACE, + "collecting paths and path exclusions", + "flags.paths" = ?flags.paths, + "flags.skip" = ?flags.skip, + "flags.exclude" = ?flags.exclude + ); + config.skip = flags .skip .into_iter() @@ -1339,6 +1372,14 @@ impl Config { }) .collect(); + #[cfg(feature = "tracing")] + span!( + target: "CONFIG_HANDLING", + tracing::Level::TRACE, + "normalizing and combining `flag.skip`/`flag.exclude` paths", + "config.skip" = ?config.skip, + ); + config.include_default_paths = flags.include_default_paths; config.rustc_error_format = flags.rustc_error_format; config.json_output = flags.json_output; diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index f17103f97dc..27fb00cb06e 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -6,6 +6,8 @@ use std::path::{Path, PathBuf}; use clap::{CommandFactory, Parser, ValueEnum}; +#[cfg(feature = "tracing")] +use tracing::instrument; use crate::core::build_steps::setup::Profile; use crate::core::builder::{Builder, Kind}; @@ -211,6 +213,10 @@ impl Flags { } } + #[cfg_attr( + feature = "tracing", + instrument(level = "trace", name = "Flags::parse", skip_all, fields(args = ?args)) + )] pub fn parse(args: &[String]) -> Self { Flags::parse_from(normalize_args(args)) } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 482e23cd04c..d56f35f866c 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -28,6 +28,8 @@ use std::{env, fs, io, str}; use build_helper::ci::gha; use build_helper::exit; use termcolor::{ColorChoice, StandardStream, WriteColor}; +#[cfg(feature = "tracing")] +use tracing::{debug, instrument, span, trace}; use utils::build_stamp::BuildStamp; use utils::channel::GitInfo; @@ -537,14 +539,25 @@ impl Build { } /// Executes the entire build, as configured by the flags and configuration. + #[cfg_attr(feature = "tracing", instrument(level = "debug", name = "Build::build", skip_all))] pub fn build(&mut self) { + #[cfg(feature = "tracing")] + trace!("setting up job management"); unsafe { crate::utils::job::setup(self); } + #[cfg(feature = "tracing")] + trace!("downloading rustfmt early"); + // Download rustfmt early so that it can be used in rust-analyzer configs. let _ = &builder::Builder::new(self).initial_rustfmt(); + #[cfg(feature = "tracing")] + let hardcoded_span = + span!(tracing::Level::DEBUG, "handling hardcoded subcommands (Format, Suggest, Perf)") + .entered(); + // hardcoded subcommands match &self.config.cmd { Subcommand::Format { check, all } => { @@ -561,25 +574,50 @@ impl Build { Subcommand::Perf { .. } => { return core::build_steps::perf::perf(&builder::Builder::new(self)); } - _ => (), + _cmd => { + #[cfg(feature = "tracing")] + debug!(cmd = ?_cmd, "not a hardcoded subcommand; returning to normal handling"); + } } + #[cfg(feature = "tracing")] + drop(hardcoded_span); + #[cfg(feature = "tracing")] + debug!("handling subcommand normally"); + if !self.config.dry_run() { + #[cfg(feature = "tracing")] + let _real_run_span = span!(tracing::Level::DEBUG, "executing real run").entered(); + { + #[cfg(feature = "tracing")] + let _sanity_check_span = + span!(tracing::Level::DEBUG, "(1) executing dry-run sanity-check").entered(); + // We first do a dry-run. This is a sanity-check to ensure that // steps don't do anything expensive in the dry-run. self.config.dry_run = DryRun::SelfCheck; let builder = builder::Builder::new(self); builder.execute_cli(); } + + #[cfg(feature = "tracing")] + let _actual_run_span = + span!(tracing::Level::DEBUG, "(2) executing actual run").entered(); self.config.dry_run = DryRun::Disabled; let builder = builder::Builder::new(self); builder.execute_cli(); } else { + #[cfg(feature = "tracing")] + let _dry_run_span = span!(tracing::Level::DEBUG, "executing dry run").entered(); + let builder = builder::Builder::new(self); builder.execute_cli(); } + #[cfg(feature = "tracing")] + debug!("checking for postponed test failures from `test --no-fail-fast`"); + // Check for postponed failures from `test --no-fail-fast`. let failures = self.delayed_failures.borrow(); if failures.len() > 0 { -- cgit 1.4.1-3-g733a5