Implement IsZero for (), and optimize `IsZero::is_zero` for arrays
These are probably not super useful optimizations, but they make it so that `vec![expr; LARGE_LENGTH]` has better performance for some `expr`s, e.g.
* array of length zero in debug mode
* tuple containing `()` and zero-valued integers in debug and release mode
* array of `()` or other zero-sized `IsZero` type in debug mode
<details> <summary>very rough benchmarks</summary>
```Rust
use std::time::Instant;
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
struct NonCopyZst;
static COUNTER: AtomicUsize = AtomicUsize::new(0);
impl Clone for NonCopyZst {
fn clone(&self) -> Self {
COUNTER.fetch_add(1, Relaxed);
Self
}
}
macro_rules! timeit {
($e:expr) => {
let start = Instant::now();
_ = $e;
println!("{:56}: {:?}", stringify!($e), start.elapsed());
};
}
fn main() {
timeit!(vec![[String::from("hello"); 0]; 1_000_000_000]); // gets a lot better in debug mode
timeit!(vec![(0u8, (), 0u16); 1_000_000_000]); // gets a lot better in debug *and* release mode
timeit!(vec![[[(); 37]; 1_000_000_000]; 1_000_000_000]); // gets a lot better in debug mode
timeit!(vec![[NonCopyZst; 0]; 1_000_000_000]); // gets a lot better in debug mode
timeit!(vec![[[1u8; 0]; 1_000_000]; 1_000_000]); // gets a little bit better in debug mode
timeit!(vec![[[(); 37]; 1_000_000]; 1_000_000]); // gets a little bit better in debug mode
timeit!(vec![[[1u128; 0]; 1_000_000]; 1_000_000]); // gets a little bit better in debug mode
// check that we don't regress existing optimizations
timeit!(vec![(0u8, 0u16); 1_000_000_000]); // about the same time
timeit!(vec![0u32; 1_000_000_000]); // about the same time
// check that we still call clone for non-IsZero ZSTs
timeit!(vec![[const { NonCopyZst }; 2]; 1_000]); // about the same time
assert_eq!(COUNTER.load(Relaxed), 1998);
timeit!(vec![NonCopyZst; 10_000]); // about the same time
assert_eq!(COUNTER.load(Relaxed), 1998 + 9_999);
}
```
```rs
$ cargo +nightly run
// ...
vec![[String::from("hello"); 0]; 1_000_000_000] : 11.13999724s
vec![(0u8, (), 0u16); 1_000_000_000] : 5.254646651s
vec![[[(); 37]; 1_000_000_000]; 1_000_000_000] : 2.738062531s
vec![[NonCopyZst; 0]; 1_000_000_000] : 9.483690922s
vec![[[1u8; 0]; 1_000_000]; 1_000_000] : 2.919236ms
vec![[[(); 37]; 1_000_000]; 1_000_000] : 2.927755ms
vec![[[1u128; 0]; 1_000_000]; 1_000_000] : 2.931486ms
vec![(0u8, 0u16); 1_000_000_000] : 19.46µs
vec![0u32; 1_000_000_000] : 9.34µs
vec![[const { NonCopyZst }; 2]; 1_000] : 31.88µs
vec![NonCopyZst; 10_000] : 36.519µs
```
```rs
$ cargo +dev run
// ...
vec![[String::from("hello"); 0]; 1_000_000_000] : 4.12µs
vec![(0u8, (), 0u16); 1_000_000_000] : 16.299µs
vec![[[(); 37]; 1_000_000_000]; 1_000_000_000] : 210ns
vec![[NonCopyZst; 0]; 1_000_000_000] : 210ns
vec![[[1u8; 0]; 1_000_000]; 1_000_000] : 170ns
vec![[[(); 37]; 1_000_000]; 1_000_000] : 110ns
vec![[[1u128; 0]; 1_000_000]; 1_000_000] : 140ns
vec![(0u8, 0u16); 1_000_000_000] : 11.56µs
vec![0u32; 1_000_000_000] : 10.71µs
vec![[const { NonCopyZst }; 2]; 1_000] : 36.08µs
vec![NonCopyZst; 10_000] : 73.21µs
```
(checking release mode to make sure this doesn't regress perf there)
```rs
$ cargo +nightly run --release
// ...
vec![[String::from("hello"); 0]; 1_000_000_000] : 70ns
vec![(0u8, (), 0u16); 1_000_000_000] : 1.269457501s
vec![[[(); 37]; 1_000_000_000]; 1_000_000_000] : 10ns
vec![[NonCopyZst; 0]; 1_000_000_000] : 20ns
vec![[[1u8; 0]; 1_000_000]; 1_000_000] : 10ns
vec![[[(); 37]; 1_000_000]; 1_000_000] : 20ns
vec![[[1u128; 0]; 1_000_000]; 1_000_000] : 20ns
vec![(0u8, 0u16); 1_000_000_000] : 20ns
vec![0u32; 1_000_000_000] : 20ns
vec![[const { NonCopyZst }; 2]; 1_000] : 2.66µs
vec![NonCopyZst; 10_000] : 13.39µs
```
```rs
$ cargo +dev run --release
vec![[String::from("hello"); 0]; 1_000_000_000] : 90ns
vec![(0u8, (), 0u16); 1_000_000_000] : 30ns
vec![[[(); 37]; 1_000_000_000]; 1_000_000_000] : 20ns
vec![[NonCopyZst; 0]; 1_000_000_000] : 30ns
vec![[[1u8; 0]; 1_000_000]; 1_000_000] : 20ns
vec![[[(); 37]; 1_000_000]; 1_000_000] : 20ns
vec![[[1u128; 0]; 1_000_000]; 1_000_000] : 20ns
vec![(0u8, 0u16); 1_000_000_000] : 30ns
vec![0u32; 1_000_000_000] : 20ns
vec![[const { NonCopyZst }; 2]; 1_000] : 3.52µs
vec![NonCopyZst; 10_000] : 17.13µs
```
</details>
The specific expression I ran into a perf issue that this PR addresses is `vec![[(); LARGE]; LARGE]`, as I was trying to demonstrate `Vec::into_flattened` panicking on length overflow in the playground, but got a timeout error instead since `vec![[(); LARGE]; LARGE]` took so long to run in debug mode (it runs fine on the playground in release mode)
|
||
|---|---|---|
| .github | ||
| compiler | ||
| library | ||
| LICENSES | ||
| src | ||
| tests | ||
| .clang-format | ||
| .editorconfig | ||
| .git-blame-ignore-revs | ||
| .gitattributes | ||
| .gitignore | ||
| .gitmodules | ||
| .ignore | ||
| .mailmap | ||
| bootstrap.example.toml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CODE_OF_CONDUCT.md | ||
| configure | ||
| CONTRIBUTING.md | ||
| COPYRIGHT | ||
| INSTALL.md | ||
| LICENSE-APACHE | ||
| license-metadata.json | ||
| LICENSE-MIT | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| RELEASES.md | ||
| REUSE.toml | ||
| rust-bors.toml | ||
| rustfmt.toml | ||
| triagebot.toml | ||
| typos.toml | ||
| x | ||
| x.ps1 | ||
| x.py | ||
This is the main source code repository for Rust. It contains the compiler, standard library, and documentation.
Why Rust?
-
Performance: Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrated with other languages.
-
Reliability: Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time.
-
Productivity: Comprehensive documentation, a compiler committed to providing great diagnostics, and advanced tooling including package manager and build tool (Cargo), auto-formatter (rustfmt), linter (Clippy) and editor support (rust-analyzer).
Quick Start
Read "Installation" from The Book.
Installing from Source
If you really want to install from source (though this is not recommended), see INSTALL.md.
Getting Help
See https://www.rust-lang.org/community for a list of chat platforms and forums.
Contributing
See CONTRIBUTING.md.
License
Rust is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), with portions covered by various BSD-like licenses.
See LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details.
Trademark
The Rust Foundation owns and protects the Rust and Cargo trademarks and logos (the "Rust Trademarks").
If you want to use these names or brands, please read the Rust language trademark policy.
Third-party logos may be subject to third-party copyrights and trademarks. See Licenses for details.