implement `Default` for `AsciiChar`
This implements `Default` for `AsciiChar` in order to match `char`'s implementation.
From all the different possible ways to do this I think the clearest one is to have both `char` and `AsciiChar` impls together.
I've also updated the doc-comment of the default variant since rustdoc doesn't seem to indicate it otherwise. Probably the text could be improved, though. I couldn't find any similar examples in the codebase and suggestions are welcomed.
r? `@scottmcm`
Clarify the lifetimes of allocations returned by the `Allocator` trait
The previous definition (accidentally) disallowed the implementation of stack-based allocators whose memory would become invalid once the lifetime of the allocator type ended.
This also ensures the validity of the following blanket implementation:
```rust
impl<A: Allocator> Allocator for &'_ A {}
```
Additional doc links and explanation of `Wake`.
This is intended to clarify:
* That `Wake` exists and can be used instead of `RawWaker`.
* How to construct a `Waker` when you are looking at `Wake` (which was previously only documented in the example).
The previous definition (accidentally) disallowed the implementation of
stack-based allocators whose memory would become invalid once the
lifetime of the allocator type ended.
This also ensures the validity of the following blanket implementation:
```rust
impl<A: Allocator> Allocator for &'_ A {}
```
assert_unsafe_precondition cleanup
I moved the polymorphic `is_nonoverlapping` into the `Cell` function that uses it and renamed `intrinsics::is_nonoverlapping_mono` to just `intrinsics::is_nonoverlapping`.
We now also have some docs for `intrinsics::debug_assertions`.
r? RalfJung
core: add Duration constructors
Add more `Duration` constructors.
Tracking issue: #120301.
These match similar convenience constructors available on both `chrono::Duration` and `time::Duration`.
What's the best ordering for these with respect to the existing constructors?
Suggest less bug-prone construction of Duration in docs
std::time::Duration has a well-known quirk: Duration::as_nanos() returns u128 [1], but Duration::from_nanos() takes u64 [2]. So these methods cannot easily roundtrip [3]. It is not possible to simply accept u128 in from_nanos [4], because it requires breaking other API [5].
It seems to me that callers have basically only two options:
1. `Duration::from_nanos(d.as_nanos() as u64)`, which is the "obvious" and buggy approach.
2. `Duration::new(d.as_secs(), d.subsecs_nanos())`, which only becomes apparent after reading and digesting the entire Duration struct documentation.
I suggest that the documentation of `from_nanos` is changed to make option 2 more easily discoverable.
There are two major usecases for this:
- "Weird math" operations that should not be supported directly by `Duration`, like squaring.
- "Disconnected roundtrips", where the u128 value is passed through various other stack frames, and perhaps reconstructed into a Duration on a different machine.
In both cases, it seems like a good idea to not tempt people into thinking "Eh, u64 is good enough, what could possibly go wrong!". That's why I want to add a note that points out the similarly-easy and *safe* way to reconstruct a Duration.
[1] https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.as_nanos
[2] https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_nanos
[3] https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fa6bab2b6b72f20c14b5243610ea1dde
[4] https://github.com/rust-lang/rust/issues/103332
[5] https://github.com/rust-lang/rust/issues/51107#issuecomment-392353166
Remove an unneeded helper from the tuple library code
Thanks to https://github.com/rust-lang/rust/pull/107022, this is just what `==` does, so we don't need the helper here anymore.
This is intended to clarify:
* That `Wake` exists and can be used instead of `RawWaker`.
* How to construct a `Waker` when you are looking at `Wake`
(which was previously only documented in the example).
Clarify that atomic and regular integers can differ in alignment
The documentation for atomic integers says that they have the "same in-memory representation" as their underlying integers. This might be misconstrued as implying that they have the same layout. Therefore, clarify that atomic integers' alignment is equal to their size.
Harmonize `AsyncFn` implementations, make async closures conditionally impl `Fn*` traits
This PR implements several changes to the built-in and libcore-provided implementations of `Fn*` and `AsyncFn*` to address two problems:
1. async closures do not implement the `Fn*` family traits, leading to breakage: https://crater-reports.s3.amazonaws.com/pr-120361/index.html
2. *references* to async closures do not implement `AsyncFn*`, as a consequence of the existing blanket impls of the shape `AsyncFn for F where F: Fn, F::Output: Future`.
In order to fix (1.), we implement `Fn` traits appropriately for async closures. It turns out that async closures can:
* always implement `FnOnce`, meaning that they're drop-in compatible with `FnOnce`-bound combinators like `Option::map`.
* conditionally implement `Fn`/`FnMut` if they have no captures, which means that existing usages of async closures should *probably* work without breakage (crater checking this: https://github.com/rust-lang/rust/pull/120712#issuecomment-1930587805).
In order to fix (2.), we make all of the built-in callables implement `AsyncFn*` via built-in impls, and instead adjust the blanket impls for `AsyncFn*` provided by libcore to match the blanket impls for `Fn*`.
Improve `Option::inspect` docs
* Refer to the function as "a function" instead of "the provided closure" since it is not necessarily a closure.
* State that the original Option/Result is returned.
* Adjust the example for `Option::inspect` to use chaining.
core/time: avoid divisions in Duration::new
In our (decently large) code base, we use `SystemTime::UNIX_EPOCH.elapsed()` in a lot of places & often in a loop or in the hot path. On [Unix](https://github.com/rust-lang/rust/blob/1.75.0/library/std/src/sys/unix/time.rs#L153-L162) at least, it seems we do calculations before hand to ensure that nanos is within the valid range, yet `Duration::new()` still checks it again, using 2 divisions. It seems like adding a branch can make this function 33% faster on ARM64 in the cases where nanos is already in the valid range & seems to have no effect in the other case.
Benchmarks:
M1 Pro (14-inch base model):
```
duration/current/checked
time: [1.5945 ns 1.6167 ns 1.6407 ns]
Found 5 outliers among 100 measurements (5.00%)
2 (2.00%) high mild
3 (3.00%) high severe
duration/current/unchecked
time: [1.5941 ns 1.6051 ns 1.6179 ns]
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
duration/branched/checked
time: [1.1997 ns 1.2048 ns 1.2104 ns]
Found 8 outliers among 100 measurements (8.00%)
4 (4.00%) high mild
4 (4.00%) high severe
duration/branched/unchecked
time: [1.5881 ns 1.5957 ns 1.6039 ns]
Found 6 outliers among 100 measurements (6.00%)
3 (3.00%) high mild
3 (3.00%) high severe
```
EC2 c7gd.16xlarge (Graviton 3):
```
duration/current/checked
time: [2.7996 ns 2.8000 ns 2.8003 ns]
Found 5 outliers among 100 measurements (5.00%)
2 (2.00%) low severe
3 (3.00%) low mild
duration/current/unchecked
time: [2.9922 ns 2.9925 ns 2.9928 ns]
Found 7 outliers among 100 measurements (7.00%)
4 (4.00%) low severe
1 (1.00%) low mild
2 (2.00%) high mild
duration/branched/checked
time: [2.0830 ns 2.0843 ns 2.0857 ns]
Found 3 outliers among 100 measurements (3.00%)
1 (1.00%) low severe
1 (1.00%) low mild
1 (1.00%) high mild
duration/branched/unchecked
time: [2.9879 ns 2.9886 ns 2.9893 ns]
Found 5 outliers among 100 measurements (5.00%)
3 (3.00%) low severe
2 (2.00%) low mild
```
EC2 r7iz.16xlarge (Intel Xeon Scalable-based (Sapphire Rapids)):
```
duration/current/checked
time: [980.60 ps 980.79 ps 980.99 ps]
Found 10 outliers among 100 measurements (10.00%)
4 (4.00%) low severe
2 (2.00%) low mild
3 (3.00%) high mild
1 (1.00%) high severe
duration/current/unchecked
time: [979.53 ps 979.74 ps 979.96 ps]
Found 6 outliers among 100 measurements (6.00%)
2 (2.00%) low severe
1 (1.00%) low mild
2 (2.00%) high mild
1 (1.00%) high severe
duration/branched/checked
time: [938.72 ps 938.96 ps 939.22 ps]
Found 4 outliers among 100 measurements (4.00%)
1 (1.00%) low mild
1 (1.00%) high mild
2 (2.00%) high severe
duration/branched/unchecked
time: [1.0103 ns 1.0110 ns 1.0118 ns]
Found 10 outliers among 100 measurements (10.00%)
2 (2.00%) low mild
7 (7.00%) high mild
1 (1.00%) high severe
```
Bench code (ran using stable 1.75.0 & criterion latest 0.5.1):
I couldn't find any benches for `Duration` in this repo, so I just copied the relevant types & recreated it.
```rust
use criterion::{black_box, criterion_group, criterion_main, Criterion};
pub fn duration_bench(c: &mut Criterion) {
const NANOS_PER_SEC: u32 = 1_000_000_000;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
struct Nanoseconds(u32);
impl Default for Nanoseconds {
#[inline]
fn default() -> Self {
// SAFETY: 0 is within the valid range
unsafe { Nanoseconds(0) }
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Duration {
secs: u64,
nanos: Nanoseconds, // Always 0 <= nanos < NANOS_PER_SEC
}
impl Duration {
#[inline]
pub const fn new_current(secs: u64, nanos: u32) -> Duration {
let secs = match secs.checked_add((nanos / NANOS_PER_SEC) as u64) {
Some(secs) => secs,
None => panic!("overflow in Duration::new"),
};
let nanos = nanos % NANOS_PER_SEC;
// SAFETY: nanos % NANOS_PER_SEC < NANOS_PER_SEC, therefore nanos is within the valid range
Duration { secs, nanos: unsafe { Nanoseconds(nanos) } }
}
#[inline]
pub const fn new_branched(secs: u64, nanos: u32) -> Duration {
if nanos < NANOS_PER_SEC {
// SAFETY: nanos < NANOS_PER_SEC, therefore nanos is within the valid range
Duration { secs, nanos: unsafe { Nanoseconds(nanos) } }
} else {
let secs = match secs.checked_add((nanos / NANOS_PER_SEC) as u64) {
Some(secs) => secs,
None => panic!("overflow in Duration::new"),
};
let nanos = nanos % NANOS_PER_SEC;
// SAFETY: nanos % NANOS_PER_SEC < NANOS_PER_SEC, therefore nanos is within the valid range
Duration { secs, nanos: unsafe { Nanoseconds(nanos) } }
}
}
}
let mut group = c.benchmark_group("duration/current");
group.bench_function("checked", |b| {
b.iter(|| black_box(Duration::new_current(black_box(1_000_000_000), black_box(1_000_000))));
});
group.bench_function("unchecked", |b| {
b.iter(|| {
black_box(Duration::new_current(black_box(1_000_000_000), black_box(2_000_000_000)))
});
});
drop(group);
let mut group = c.benchmark_group("duration/branched");
group.bench_function("checked", |b| {
b.iter(|| {
black_box(Duration::new_branched(black_box(1_000_000_000), black_box(1_000_000)))
});
});
group.bench_function("unchecked", |b| {
b.iter(|| {
black_box(Duration::new_branched(black_box(1_000_000_000), black_box(2_000_000_000)))
});
});
}
criterion_group!(duration_benches, duration_bench);
criterion_main!(duration_benches);
```
The documentation for atomic integers says that they have the "same
in-memory representation" as their underlying integers. This might be
misconstrued as implying that they have the same layout. Therefore,
clarify that atomic integers' alignment is equal to their size.