summaryrefslogtreecommitdiffstats
path: root/library/core
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:28 +0000
commit94a0819fe3a0d679c3042a77bfe6a2afc505daea (patch)
tree2b827afe6a05f3538db3f7803a88c4587fe85648 /library/core
parentAdding upstream version 1.64.0+dfsg1. (diff)
downloadrustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.tar.xz
rustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.zip
Adding upstream version 1.66.0+dfsg1.upstream/1.66.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core')
-rw-r--r--library/core/benches/iter.rs27
-rw-r--r--library/core/benches/lib.rs1
-rw-r--r--library/core/benches/num/int_log/mod.rs6
-rw-r--r--library/core/src/alloc/global.rs2
-rw-r--r--library/core/src/alloc/layout.rs114
-rw-r--r--library/core/src/alloc/mod.rs9
-rw-r--r--library/core/src/any.rs244
-rw-r--r--library/core/src/array/equality.rs7
-rw-r--r--library/core/src/array/iter.rs59
-rw-r--r--library/core/src/array/mod.rs68
-rw-r--r--library/core/src/bool.rs29
-rw-r--r--library/core/src/borrow.rs4
-rw-r--r--library/core/src/cell.rs74
-rw-r--r--library/core/src/char/decode.rs9
-rw-r--r--library/core/src/char/methods.rs62
-rw-r--r--library/core/src/char/mod.rs8
-rw-r--r--library/core/src/cmp.rs125
-rw-r--r--library/core/src/const_closure.rs77
-rw-r--r--library/core/src/convert/mod.rs224
-rw-r--r--library/core/src/default.rs3
-rw-r--r--library/core/src/error.md137
-rw-r--r--library/core/src/error.rs508
-rw-r--r--library/core/src/ffi/c_double.md4
-rw-r--r--library/core/src/ffi/c_float.md4
-rw-r--r--library/core/src/ffi/c_str.rs105
-rw-r--r--library/core/src/fmt/builders.rs18
-rw-r--r--library/core/src/fmt/mod.rs18
-rw-r--r--library/core/src/fmt/num.rs92
-rw-r--r--library/core/src/future/poll_fn.rs11
-rw-r--r--library/core/src/future/ready.rs24
-rw-r--r--library/core/src/hash/mod.rs2
-rw-r--r--library/core/src/hint.rs28
-rw-r--r--library/core/src/intrinsics.rs530
-rw-r--r--library/core/src/iter/adapters/array_chunks.rs170
-rw-r--r--library/core/src/iter/adapters/by_ref_sized.rs42
-rw-r--r--library/core/src/iter/adapters/copied.rs74
-rw-r--r--library/core/src/iter/adapters/flatten.rs375
-rw-r--r--library/core/src/iter/adapters/map_while.rs14
-rw-r--r--library/core/src/iter/adapters/mod.rs14
-rw-r--r--library/core/src/iter/adapters/scan.rs14
-rw-r--r--library/core/src/iter/adapters/skip.rs39
-rw-r--r--library/core/src/iter/adapters/take.rs14
-rw-r--r--library/core/src/iter/adapters/take_while.rs14
-rw-r--r--library/core/src/iter/mod.rs25
-rw-r--r--library/core/src/iter/range.rs28
-rw-r--r--library/core/src/iter/traits/collect.rs3
-rw-r--r--library/core/src/iter/traits/iterator.rs215
-rw-r--r--library/core/src/lazy.rs1
-rw-r--r--library/core/src/lib.rs23
-rw-r--r--library/core/src/macros/mod.rs53
-rw-r--r--library/core/src/marker.rs134
-rw-r--r--library/core/src/mem/maybe_uninit.rs54
-rw-r--r--library/core/src/mem/mod.rs95
-rw-r--r--library/core/src/mem/transmutability.rs88
-rw-r--r--library/core/src/num/bignum.rs2
-rw-r--r--library/core/src/num/dec2flt/decimal.rs2
-rw-r--r--library/core/src/num/dec2flt/lemire.rs4
-rw-r--r--library/core/src/num/error.rs17
-rw-r--r--library/core/src/num/f32.rs153
-rw-r--r--library/core/src/num/f64.rs153
-rw-r--r--library/core/src/num/flt2dec/strategy/grisu.rs4
-rw-r--r--library/core/src/num/int_log10.rs2
-rw-r--r--library/core/src/num/int_macros.rs212
-rw-r--r--library/core/src/num/mod.rs76
-rw-r--r--library/core/src/num/nonzero.rs203
-rw-r--r--library/core/src/num/uint_macros.rs189
-rw-r--r--library/core/src/ops/arith.rs50
-rw-r--r--library/core/src/ops/bit.rs11
-rw-r--r--library/core/src/ops/control_flow.rs9
-rw-r--r--library/core/src/ops/deref.rs2
-rw-r--r--library/core/src/ops/drop.rs3
-rw-r--r--library/core/src/ops/function.rs28
-rw-r--r--library/core/src/ops/generator.rs1
-rw-r--r--library/core/src/ops/index.rs2
-rw-r--r--library/core/src/ops/index_range.rs171
-rw-r--r--library/core/src/ops/mod.rs3
-rw-r--r--library/core/src/ops/range.rs2
-rw-r--r--library/core/src/ops/try_trait.rs36
-rw-r--r--library/core/src/option.rs52
-rw-r--r--library/core/src/panic/location.rs9
-rw-r--r--library/core/src/panicking.rs130
-rw-r--r--library/core/src/primitive_docs.rs95
-rw-r--r--library/core/src/ptr/alignment.rs (renamed from library/core/src/mem/valid_align.rs)175
-rw-r--r--library/core/src/ptr/const_ptr.rs111
-rw-r--r--library/core/src/ptr/metadata.rs32
-rw-r--r--library/core/src/ptr/mod.rs130
-rw-r--r--library/core/src/ptr/mut_ptr.rs105
-rw-r--r--library/core/src/ptr/non_null.rs6
-rw-r--r--library/core/src/result.rs73
-rw-r--r--library/core/src/slice/ascii.rs2
-rw-r--r--library/core/src/slice/index.rs112
-rw-r--r--library/core/src/slice/iter.rs25
-rw-r--r--library/core/src/slice/iter/macros.rs26
-rw-r--r--library/core/src/slice/memchr.rs41
-rw-r--r--library/core/src/slice/mod.rs177
-rw-r--r--library/core/src/slice/raw.rs38
-rw-r--r--library/core/src/slice/rotate.rs4
-rw-r--r--library/core/src/slice/sort.rs42
-rw-r--r--library/core/src/str/error.rs17
-rw-r--r--library/core/src/str/lossy.rs244
-rw-r--r--library/core/src/str/mod.rs13
-rw-r--r--library/core/src/str/pattern.rs2
-rw-r--r--library/core/src/str/traits.rs18
-rw-r--r--library/core/src/str/validations.rs4
-rw-r--r--library/core/src/sync/atomic.rs134
-rw-r--r--library/core/src/sync/exclusive.rs9
-rw-r--r--library/core/src/task/wake.rs59
-rw-r--r--library/core/src/time.rs198
-rw-r--r--library/core/src/tuple.rs5
-rw-r--r--library/core/src/unicode/printable.rs131
-rw-r--r--library/core/src/unicode/unicode_data.rs293
-rw-r--r--library/core/tests/alloc.rs44
-rw-r--r--library/core/tests/any.rs2
-rw-r--r--library/core/tests/ascii.rs18
-rw-r--r--library/core/tests/atomic.rs2
-rw-r--r--library/core/tests/const_ptr.rs6
-rw-r--r--library/core/tests/iter/adapters/array_chunks.rs179
-rw-r--r--library/core/tests/iter/adapters/by_ref_sized.rs20
-rw-r--r--library/core/tests/iter/adapters/flatten.rs42
-rw-r--r--library/core/tests/iter/adapters/mod.rs24
-rw-r--r--library/core/tests/iter/adapters/skip.rs31
-rw-r--r--library/core/tests/lib.rs15
-rw-r--r--library/core/tests/mem.rs12
-rw-r--r--library/core/tests/num/int_log.rs186
-rw-r--r--library/core/tests/num/int_macros.rs26
-rw-r--r--library/core/tests/num/mod.rs2
-rw-r--r--library/core/tests/num/uint_macros.rs22
-rw-r--r--library/core/tests/num/wrapping.rs2
-rw-r--r--library/core/tests/option.rs1
-rw-r--r--library/core/tests/panic.rs1
-rw-r--r--library/core/tests/panic/location.rs31
-rw-r--r--library/core/tests/ptr.rs2
-rw-r--r--library/core/tests/result.rs9
-rw-r--r--library/core/tests/slice.rs4
-rw-r--r--library/core/tests/str_lossy.rs138
-rw-r--r--library/core/tests/task.rs17
-rw-r--r--library/core/tests/time.rs32
137 files changed, 6203 insertions, 2634 deletions
diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs
index 0abe20e4c..38887f29a 100644
--- a/library/core/benches/iter.rs
+++ b/library/core/benches/iter.rs
@@ -1,4 +1,6 @@
use core::iter::*;
+use core::mem;
+use core::num::Wrapping;
use test::{black_box, Bencher};
#[bench]
@@ -364,6 +366,13 @@ fn bench_partial_cmp(b: &mut Bencher) {
}
#[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)))
}
@@ -391,3 +400,21 @@ fn bench_trusted_random_access_adapters(b: &mut Bencher) {
acc
})
}
+
+/// Exercises the iter::Copied specialization for slice::Iter
+#[bench]
+fn bench_copied_array_chunks(b: &mut Bencher) {
+ let v = vec![1u8; 1024];
+
+ b.iter(|| {
+ black_box(&v)
+ .iter()
+ .copied()
+ .array_chunks::<{ mem::size_of::<u64>() }>()
+ .map(|ary| {
+ let d = u64::from_ne_bytes(ary);
+ Wrapping(d.rotate_left(7).wrapping_add(1))
+ })
+ .sum::<Wrapping<u64>>()
+ })
+}
diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs
index a6c174d2f..1e462e3fc 100644
--- a/library/core/benches/lib.rs
+++ b/library/core/benches/lib.rs
@@ -4,6 +4,7 @@
#![feature(int_log)]
#![feature(test)]
#![feature(trusted_random_access)]
+#![feature(iter_array_chunks)]
extern crate test;
diff --git a/library/core/benches/num/int_log/mod.rs b/library/core/benches/num/int_log/mod.rs
index 19864d2d4..3c01e2998 100644
--- a/library/core/benches/num/int_log/mod.rs
+++ b/library/core/benches/num/int_log/mod.rs
@@ -9,7 +9,7 @@ macro_rules! int_log_bench {
for n in 0..(<$t>::BITS / 8) {
for i in 1..=(100 as $t) {
let x = black_box(i << (n * 8));
- black_box(x.log10());
+ black_box(x.ilog10());
}
}
});
@@ -27,7 +27,7 @@ macro_rules! int_log_bench {
.collect();
bench.iter(|| {
for x in &numbers {
- black_box(black_box(x).log10());
+ black_box(black_box(x).ilog10());
}
});
}
@@ -44,7 +44,7 @@ macro_rules! int_log_bench {
.collect();
bench.iter(|| {
for x in &numbers {
- black_box(black_box(x).log10());
+ black_box(black_box(x).ilog10());
}
});
}
diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs
index 887246c60..6756eecd0 100644
--- a/library/core/src/alloc/global.rs
+++ b/library/core/src/alloc/global.rs
@@ -74,7 +74,7 @@ use crate::ptr;
/// {
/// return null_mut();
/// };
-/// (self.arena.get() as *mut u8).add(allocated)
+/// self.arena.get().cast::<u8>().add(allocated)
/// }
/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
/// }
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 2f378836c..920e559cc 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -1,4 +1,11 @@
+// Seemingly inconsequential code changes to this file can lead to measurable
+// performance impact on compilation times, due at least in part to the fact
+// that the layout code gets called from many instantiations of the various
+// collections, resulting in having to optimize down excess IR multiple times.
+// Your performance intuition is useless. Run perf.
+
use crate::cmp;
+use crate::error::Error;
use crate::fmt;
use crate::mem::{self, ValidAlign};
use crate::ptr::NonNull;
@@ -52,16 +59,23 @@ impl Layout {
/// * `align` must be a power of two,
///
/// * `size`, when rounded up to the nearest multiple of `align`,
- /// must not overflow (i.e., the rounded value must be less than
- /// or equal to `usize::MAX`).
+ /// must not overflow isize (i.e., the rounded value must be
+ /// less than or equal to `isize::MAX`).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
#[inline]
+ #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
if !align.is_power_of_two() {
return Err(LayoutError);
}
+ // SAFETY: just checked that align is a power of two.
+ Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) })
+ }
+
+ #[inline(always)]
+ const fn max_size_for_align(align: ValidAlign) -> usize {
// (power-of-two implies align != 0.)
// Rounded up size is:
@@ -76,13 +90,18 @@ impl Layout {
//
// Above implies that checking for summation overflow is both
// necessary and sufficient.
- if size > usize::MAX - (align - 1) {
+ isize::MAX as usize - (align.as_usize() - 1)
+ }
+
+ /// Internal helper constructor to skip revalidating alignment validity.
+ #[inline]
+ const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> {
+ if size > Self::max_size_for_align(align) {
return Err(LayoutError);
}
- // SAFETY: the conditions for `from_size_align_unchecked` have been
- // checked above.
- unsafe { Ok(Layout::from_size_align_unchecked(size, align)) }
+ // SAFETY: Layout::size invariants checked above.
+ Ok(Layout { size, align })
}
/// Creates a layout, bypassing all checks.
@@ -95,9 +114,10 @@ impl Layout {
#[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")]
#[must_use]
#[inline]
+ #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
- // SAFETY: the caller must ensure that `align` is a power of two.
- Layout { size, align: unsafe { ValidAlign::new_unchecked(align) } }
+ // SAFETY: the caller is required to uphold the preconditions.
+ unsafe { Layout { size, align: ValidAlign::new_unchecked(align) } }
}
/// The minimum size in bytes for a memory block of this layout.
@@ -115,8 +135,9 @@ impl Layout {
#[must_use = "this returns the minimum alignment, \
without modifying the layout"]
#[inline]
+ #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
pub const fn align(&self) -> usize {
- self.align.as_nonzero().get()
+ self.align.as_usize()
}
/// Constructs a `Layout` suitable for holding a value of type `T`.
@@ -126,10 +147,9 @@ impl Layout {
#[inline]
pub const fn new<T>() -> Self {
let (size, align) = size_align::<T>();
- // SAFETY: the align is guaranteed by Rust to be a power of two and
- // the size+align combo is guaranteed to fit in our address space. As a
- // result use the unchecked constructor here to avoid inserting code
- // that panics if it isn't optimized well enough.
+ // SAFETY: if the type is instantiated, rustc already ensures that its
+ // layout is valid. Use the unchecked constructor to avoid inserting a
+ // panicking codepath that needs to be optimized out.
unsafe { Layout::from_size_align_unchecked(size, align) }
}
@@ -141,7 +161,6 @@ impl Layout {
#[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
- debug_assert!(Layout::from_size_align(size, align).is_ok());
// SAFETY: see rationale in `new` for why this is using the unsafe variant
unsafe { Layout::from_size_align_unchecked(size, align) }
}
@@ -176,7 +195,6 @@ impl Layout {
pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
// SAFETY: we pass along the prerequisites of these functions to the caller
let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
- debug_assert!(Layout::from_size_align(size, align).is_ok());
// SAFETY: see rationale in `new` for why this is using the unsafe variant
unsafe { Layout::from_size_align_unchecked(size, align) }
}
@@ -276,12 +294,11 @@ impl Layout {
let pad = self.padding_needed_for(self.align());
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
- // > must not overflow (i.e., the rounded value must be less than
- // > `usize::MAX`)
+ // > must not overflow isize (i.e., the rounded value must be
+ // > less than or equal to `isize::MAX`)
let new_size = self.size() + pad;
- // SAFETY: self.align is already known to be valid and new_size has been
- // padded already.
+ // SAFETY: padded size is guaranteed to not exceed `isize::MAX`.
unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
}
@@ -298,14 +315,13 @@ impl Layout {
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
// This cannot overflow. Quoting from the invariant of Layout:
// > `size`, when rounded up to the nearest multiple of `align`,
- // > must not overflow (i.e., the rounded value must be less than
- // > `usize::MAX`)
+ // > must not overflow isize (i.e., the rounded value must be
+ // > less than or equal to `isize::MAX`)
let padded_size = self.size() + self.padding_needed_for(self.align());
let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?;
- // SAFETY: self.align is already known to be valid and alloc_size has been
- // padded already.
- unsafe { Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) }
+ // The safe constructor is called here to enforce the isize size limit.
+ Layout::from_size_valid_align(alloc_size, self.align).map(|layout| (layout, padded_size))
}
/// Creates a layout describing the record for `self` followed by
@@ -356,13 +372,14 @@ impl Layout {
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
#[inline]
pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
- let new_align = cmp::max(self.align(), next.align());
+ let new_align = cmp::max(self.align, next.align);
let pad = self.padding_needed_for(next.align());
let offset = self.size().checked_add(pad).ok_or(LayoutError)?;
let new_size = offset.checked_add(next.size()).ok_or(LayoutError)?;
- let layout = Layout::from_size_align(new_size, new_align)?;
+ // The safe constructor is called here to enforce the isize size limit.
+ let layout = Layout::from_size_valid_align(new_size, new_align)?;
Ok((layout, offset))
}
@@ -382,7 +399,8 @@ impl Layout {
#[inline]
pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
let size = self.size().checked_mul(n).ok_or(LayoutError)?;
- Layout::from_size_align(size, self.align())
+ // The safe constructor is called here to enforce the isize size limit.
+ Layout::from_size_valid_align(size, self.align)
}
/// Creates a layout describing the record for `self` followed by
@@ -395,26 +413,39 @@ impl Layout {
#[inline]
pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?;
- Layout::from_size_align(new_size, self.align())
+ // The safe constructor is called here to enforce the isize size limit.
+ Layout::from_size_valid_align(new_size, self.align)
}
/// Creates a layout describing the record for a `[T; n]`.
///
- /// On arithmetic overflow, returns `LayoutError`.
+ /// On arithmetic overflow or when the total size would exceed
+ /// `isize::MAX`, returns `LayoutError`.
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
#[inline]
pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
- let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
-
- // SAFETY:
- // - Size: `array_size` cannot be too big because `size_of::<T>()` must
- // be a multiple of `align_of::<T>()`. Therefore, `array_size`
- // rounded up to the nearest multiple of `align_of::<T>()` is just
- // `array_size`. And `array_size` cannot be too big because it was
- // just checked by the `checked_mul()`.
- // - Alignment: `align_of::<T>()` will always give an acceptable
- // (non-zero, power of two) alignment.
- Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) })
+ // Reduce the amount of code we need to monomorphize per `T`.
+ return inner(mem::size_of::<T>(), ValidAlign::of::<T>(), n);
+
+ #[inline]
+ fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result<Layout, LayoutError> {
+ // We need to check two things about the size:
+ // - That the total size won't overflow a `usize`, and
+ // - That the total size still fits in an `isize`.
+ // By using division we can check them both with a single threshold.
+ // That'd usually be a bad idea, but thankfully here the element size
+ // and alignment are constants, so the compiler will fold all of it.
+ if element_size != 0 && n > Layout::max_size_for_align(align) / element_size {
+ return Err(LayoutError);
+ }
+
+ let array_size = element_size * n;
+
+ // SAFETY: We just checked above that the `array_size` will not
+ // exceed `isize::MAX` even when rounded up to the alignment.
+ // And `ValidAlign` guarantees it's a power of two.
+ unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
+ }
}
}
@@ -434,6 +465,9 @@ pub type LayoutErr = LayoutError;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutError;
+#[stable(feature = "alloc_layout", since = "1.28.0")]
+impl Error for LayoutError {}
+
// (we need this for downstream impl of trait Error)
#[stable(feature = "alloc_layout", since = "1.28.0")]
impl fmt::Display for LayoutError {
diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs
index 6cc6e359e..a4bf6a853 100644
--- a/library/core/src/alloc/mod.rs
+++ b/library/core/src/alloc/mod.rs
@@ -21,6 +21,7 @@ pub use self::layout::LayoutErr;
#[stable(feature = "alloc_layout_error", since = "1.50.0")]
pub use self::layout::LayoutError;
+use crate::error::Error;
use crate::fmt;
use crate::ptr::{self, NonNull};
@@ -32,6 +33,13 @@ use crate::ptr::{self, NonNull};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct AllocError;
+#[unstable(
+ feature = "allocator_api",
+ reason = "the precise API and guarantees it provides may be tweaked.",
+ issue = "32838"
+)]
+impl Error for AllocError {}
+
// (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for AllocError {
@@ -97,6 +105,7 @@ impl fmt::Display for AllocError {
///
/// [*currently allocated*]: #currently-allocated-memory
#[unstable(feature = "allocator_api", issue = "32838")]
+#[const_trait]
pub unsafe trait Allocator {
/// Attempts to allocate a block of memory.
///
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index f20c497a1..1a379ecc1 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -1,7 +1,4 @@
-//! This module contains the `Any` trait, which enables dynamic typing
-//! of any `'static` type through runtime reflection. It also contains the
-//! `Provider` trait and accompanying API, which enable trait objects to provide
-//! data based on typed requests, an alternate form of runtime reflection.
+//! Utilities for dynamic typing or type reflection.
//!
//! # `Any` and `TypeId`
//!
@@ -799,7 +796,7 @@ pub trait Provider {
/// impl Provider for SomeConcreteType {
/// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
/// demand.provide_ref::<str>(&self.field)
- /// .provide_value::<i32>(|| self.num_field);
+ /// .provide_value::<i32>(self.num_field);
/// }
/// }
/// ```
@@ -884,28 +881,55 @@ impl<'a> Demand<'a> {
///
/// # Examples
///
+ /// Provides an `u8`.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ /// # struct SomeConcreteType { field: u8 }
+ ///
+ /// impl Provider for SomeConcreteType {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// demand.provide_value::<u8>(self.field);
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn provide_value<T>(&mut self, value: T) -> &mut Self
+ where
+ T: 'static,
+ {
+ self.provide::<tags::Value<T>>(value)
+ }
+
+ /// Provide a value or other type with only static lifetimes computed using a closure.
+ ///
+ /// # Examples
+ ///
/// Provides a `String` by cloning.
///
/// ```rust
- /// # #![feature(provide_any)]
+ /// #![feature(provide_any)]
+ ///
/// use std::any::{Provider, Demand};
/// # struct SomeConcreteType { field: String }
///
/// impl Provider for SomeConcreteType {
/// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
- /// demand.provide_value::<String>(|| self.field.clone());
+ /// demand.provide_value_with::<String>(|| self.field.clone());
/// }
/// }
/// ```
#[unstable(feature = "provide_any", issue = "96024")]
- pub fn provide_value<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
+ pub fn provide_value_with<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
where
T: 'static,
{
self.provide_with::<tags::Value<T>>(fulfil)
}
- /// Provide a reference, note that the referee type must be bounded by `'static`,
+ /// Provide a reference. The referee type must be bounded by `'static`,
/// but may be unsized.
///
/// # Examples
@@ -913,7 +937,8 @@ impl<'a> Demand<'a> {
/// Provides a reference to a field as a `&str`.
///
/// ```rust
- /// # #![feature(provide_any)]
+ /// #![feature(provide_any)]
+ ///
/// use std::any::{Provider, Demand};
/// # struct SomeConcreteType { field: String }
///
@@ -928,6 +953,40 @@ impl<'a> Demand<'a> {
self.provide::<tags::Ref<tags::MaybeSizedValue<T>>>(value)
}
+ /// Provide a reference computed using a closure. The referee type
+ /// must be bounded by `'static`, but may be unsized.
+ ///
+ /// # Examples
+ ///
+ /// Provides a reference to a field as a `&str`.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ /// # struct SomeConcreteType { business: String, party: String }
+ /// # fn today_is_a_weekday() -> bool { true }
+ ///
+ /// impl Provider for SomeConcreteType {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// demand.provide_ref_with::<str>(|| {
+ /// if today_is_a_weekday() {
+ /// &self.business
+ /// } else {
+ /// &self.party
+ /// }
+ /// });
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn provide_ref_with<T: ?Sized + 'static>(
+ &mut self,
+ fulfil: impl FnOnce() -> &'a T,
+ ) -> &mut Self {
+ self.provide_with::<tags::Ref<tags::MaybeSizedValue<T>>>(fulfil)
+ }
+
/// Provide a value with the given `Type` tag.
fn provide<I>(&mut self, value: I::Reified) -> &mut Self
where
@@ -949,6 +1008,156 @@ impl<'a> Demand<'a> {
}
self
}
+
+ /// Check if the `Demand` would be satisfied if provided with a
+ /// value of the specified type. If the type does not match or has
+ /// already been provided, returns false.
+ ///
+ /// # Examples
+ ///
+ /// Check if an `u8` still needs to be provided and then provides
+ /// it.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ ///
+ /// struct Parent(Option<u8>);
+ ///
+ /// impl Provider for Parent {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// if let Some(v) = self.0 {
+ /// demand.provide_value::<u8>(v);
+ /// }
+ /// }
+ /// }
+ ///
+ /// struct Child {
+ /// parent: Parent,
+ /// }
+ ///
+ /// impl Child {
+ /// // Pretend that this takes a lot of resources to evaluate.
+ /// fn an_expensive_computation(&self) -> Option<u8> {
+ /// Some(99)
+ /// }
+ /// }
+ ///
+ /// impl Provider for Child {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// // In general, we don't know if this call will provide
+ /// // an `u8` value or not...
+ /// self.parent.provide(demand);
+ ///
+ /// // ...so we check to see if the `u8` is needed before
+ /// // we run our expensive computation.
+ /// if demand.would_be_satisfied_by_value_of::<u8>() {
+ /// if let Some(v) = self.an_expensive_computation() {
+ /// demand.provide_value::<u8>(v);
+ /// }
+ /// }
+ ///
+ /// // The demand will be satisfied now, regardless of if
+ /// // the parent provided the value or we did.
+ /// assert!(!demand.would_be_satisfied_by_value_of::<u8>());
+ /// }
+ /// }
+ ///
+ /// let parent = Parent(Some(42));
+ /// let child = Child { parent };
+ /// assert_eq!(Some(42), std::any::request_value::<u8>(&child));
+ ///
+ /// let parent = Parent(None);
+ /// let child = Child { parent };
+ /// assert_eq!(Some(99), std::any::request_value::<u8>(&child));
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn would_be_satisfied_by_value_of<T>(&self) -> bool
+ where
+ T: 'static,
+ {
+ self.would_be_satisfied_by::<tags::Value<T>>()
+ }
+
+ /// Check if the `Demand` would be satisfied if provided with a
+ /// reference to a value of the specified type. If the type does
+ /// not match or has already been provided, returns false.
+ ///
+ /// # Examples
+ ///
+ /// Check if a `&str` still needs to be provided and then provides
+ /// it.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ ///
+ /// struct Parent(Option<String>);
+ ///
+ /// impl Provider for Parent {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// if let Some(v) = &self.0 {
+ /// demand.provide_ref::<str>(v);
+ /// }
+ /// }
+ /// }
+ ///
+ /// struct Child {
+ /// parent: Parent,
+ /// name: String,
+ /// }
+ ///
+ /// impl Child {
+ /// // Pretend that this takes a lot of resources to evaluate.
+ /// fn an_expensive_computation(&self) -> Option<&str> {
+ /// Some(&self.name)
+ /// }
+ /// }
+ ///
+ /// impl Provider for Child {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// // In general, we don't know if this call will provide
+ /// // a `str` reference or not...
+ /// self.parent.provide(demand);
+ ///
+ /// // ...so we check to see if the `&str` is needed before
+ /// // we run our expensive computation.
+ /// if demand.would_be_satisfied_by_ref_of::<str>() {
+ /// if let Some(v) = self.an_expensive_computation() {
+ /// demand.provide_ref::<str>(v);
+ /// }
+ /// }
+ ///
+ /// // The demand will be satisfied now, regardless of if
+ /// // the parent provided the reference or we did.
+ /// assert!(!demand.would_be_satisfied_by_ref_of::<str>());
+ /// }
+ /// }
+ ///
+ /// let parent = Parent(Some("parent".into()));
+ /// let child = Child { parent, name: "child".into() };
+ /// assert_eq!(Some("parent"), std::any::request_ref::<str>(&child));
+ ///
+ /// let parent = Parent(None);
+ /// let child = Child { parent, name: "child".into() };
+ /// assert_eq!(Some("child"), std::any::request_ref::<str>(&child));
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn would_be_satisfied_by_ref_of<T>(&self) -> bool
+ where
+ T: ?Sized + 'static,
+ {
+ self.would_be_satisfied_by::<tags::Ref<tags::MaybeSizedValue<T>>>()
+ }
+
+ fn would_be_satisfied_by<I>(&self) -> bool
+ where
+ I: tags::Type<'a>,
+ {
+ matches!(self.0.downcast::<I>(), Some(TaggedOption(None)))
+ }
}
#[unstable(feature = "provide_any", issue = "96024")]
@@ -1053,6 +1262,21 @@ impl<'a> dyn Erased<'a> + 'a {
/// Returns some reference to the dynamic value if it is tagged with `I`,
/// or `None` otherwise.
#[inline]
+ fn downcast<I>(&self) -> Option<&TaggedOption<'a, I>>
+ where
+ I: tags::Type<'a>,
+ {
+ if self.tag_id() == TypeId::of::<I>() {
+ // SAFETY: Just checked whether we're pointing to an I.
+ Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() })
+ } else {
+ None
+ }
+ }
+
+ /// Returns some mutable reference to the dynamic value if it is tagged with `I`,
+ /// or `None` otherwise.
+ #[inline]
fn downcast_mut<I>(&mut self) -> Option<&mut TaggedOption<'a, I>>
where
I: tags::Type<'a>,
diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs
index 33f7f494e..b2c895f88 100644
--- a/library/core/src/array/equality.rs
+++ b/library/core/src/array/equality.rs
@@ -173,13 +173,14 @@ macro_rules! is_raw_eq_comparable {
)+};
}
-// SAFETY: All the ordinary integer types allow all bit patterns as distinct values
+// SAFETY: All the ordinary integer types have no padding, and are not pointers.
is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
-// SAFETY: bool and char have *niches*, but no *padding*, so this is sound
+// SAFETY: bool and char have *niches*, but no *padding* (and these are not pointer types), so this
+// is sound
is_raw_eq_comparable!(bool, char);
-// SAFETY: Similarly, the non-zero types have a niche, but no undef,
+// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers,
// and they compare like their underlying numeric type.
is_raw_eq_comparable!(
NonZeroU8,
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index f4885ed9f..b91c63018 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -1,10 +1,10 @@
//! Defines the `IntoIter` owned iterator for arrays.
use crate::{
- cmp, fmt,
+ fmt,
iter::{self, ExactSizeIterator, FusedIterator, TrustedLen},
mem::{self, MaybeUninit},
- ops::Range,
+ ops::{IndexRange, Range},
ptr,
};
@@ -29,9 +29,10 @@ pub struct IntoIter<T, const N: usize> {
/// The elements in `data` that have not been yielded yet.
///
/// Invariants:
- /// - `alive.start <= alive.end`
/// - `alive.end <= N`
- alive: Range<usize>,
+ ///
+ /// (And the `IndexRange` type requires `alive.start <= alive.end`.)
+ alive: IndexRange,
}
// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
@@ -69,7 +70,7 @@ impl<T, const N: usize> IntoIterator for [T; N] {
// Until then, we can use `mem::transmute_copy` to create a bitwise copy
// as a different type, then forget `array` so that it is not dropped.
unsafe {
- let iter = IntoIter { data: mem::transmute_copy(&self), alive: 0..N };
+ let iter = IntoIter { data: mem::transmute_copy(&self), alive: IndexRange::zero_to(N) };
mem::forget(self);
iter
}
@@ -103,8 +104,7 @@ impl<T, const N: usize> IntoIter<T, N> {
///
/// ```
/// #![feature(array_into_iter_constructors)]
- ///
- /// #![feature(maybe_uninit_array_assume_init)]
+ /// #![feature(maybe_uninit_uninit_array_transpose)]
/// #![feature(maybe_uninit_uninit_array)]
/// use std::array::IntoIter;
/// use std::mem::MaybeUninit;
@@ -133,7 +133,7 @@ impl<T, const N: usize> IntoIter<T, N> {
/// }
///
/// // SAFETY: We've initialized all N items
- /// unsafe { Ok(MaybeUninit::array_assume_init(buffer)) }
+ /// unsafe { Ok(buffer.transpose().assume_init()) }
/// }
///
/// let r: [_; 4] = next_chunk(&mut (10..16)).unwrap();
@@ -147,7 +147,9 @@ impl<T, const N: usize> IntoIter<T, N> {
buffer: [MaybeUninit<T>; N],
initialized: Range<usize>,
) -> Self {
- Self { data: buffer, alive: initialized }
+ // SAFETY: one of our safety conditions is that the range is canonical.
+ let alive = unsafe { IndexRange::new_unchecked(initialized.start, initialized.end) };
+ Self { data: buffer, alive }
}
/// Creates an iterator over `T` which returns no elements.
@@ -283,16 +285,11 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
}
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
- let len = self.len();
-
- // The number of elements to drop. Always in-bounds by construction.
- let delta = cmp::min(n, len);
+ let original_len = self.len();
- let range_to_drop = self.alive.start..(self.alive.start + delta);
-
- // Moving the start marks them as conceptually "dropped", so if anything
- // goes bad then our drop impl won't double-free them.
- self.alive.start += delta;
+ // This also moves the start, which marks them as conceptually "dropped",
+ // so if anything goes bad then our drop impl won't double-free them.
+ let range_to_drop = self.alive.take_prefix(n);
// SAFETY: These elements are currently initialized, so it's fine to drop them.
unsafe {
@@ -300,7 +297,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
}
- if n > len { Err(len) } else { Ok(()) }
+ if n > original_len { Err(original_len) } else { Ok(()) }
}
}
@@ -338,16 +335,11 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
}
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
- let len = self.len();
-
- // The number of elements to drop. Always in-bounds by construction.
- let delta = cmp::min(n, len);
-
- let range_to_drop = (self.alive.end - delta)..self.alive.end;
+ let original_len = self.len();
- // Moving the end marks them as conceptually "dropped", so if anything
- // goes bad then our drop impl won't double-free them.
- self.alive.end -= delta;
+ // This also moves the end, which marks them as conceptually "dropped",
+ // so if anything goes bad then our drop impl won't double-free them.
+ let range_to_drop = self.alive.take_suffix(n);
// SAFETY: These elements are currently initialized, so it's fine to drop them.
unsafe {
@@ -355,7 +347,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
}
- if n > len { Err(len) } else { Ok(()) }
+ if n > original_len { Err(original_len) } else { Ok(()) }
}
}
@@ -372,9 +364,7 @@ impl<T, const N: usize> Drop for IntoIter<T, N> {
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
fn len(&self) -> usize {
- // Will never underflow due to the invariant `alive.start <=
- // alive.end`.
- self.alive.end - self.alive.start
+ self.alive.len()
}
fn is_empty(&self) -> bool {
self.alive.is_empty()
@@ -396,14 +386,15 @@ impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
fn clone(&self) -> Self {
// Note, we don't really need to match the exact same alive range, so
// we can just clone into offset 0 regardless of where `self` is.
- let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 };
+ let mut new = Self { data: MaybeUninit::uninit_array(), alive: IndexRange::zero_to(0) };
// Clone all alive elements.
for (src, dst) in iter::zip(self.as_slice(), &mut new.data) {
// Write a clone into the new array, then update its alive range.
// If cloning panics, we'll correctly drop the previous items.
dst.write(src.clone());
- new.alive.end += 1;
+ // This addition cannot overflow as we're iterating a slice
+ new.alive = IndexRange::zero_to(new.alive.end() + 1);
}
new
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index c9823a136..eae0e1c76 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -1,4 +1,4 @@
-//! Helper functions and types for fixed-length arrays.
+//! Utilities for the array primitive type.
//!
//! *[See also the array primitive type](array).*
@@ -7,6 +7,7 @@
use crate::borrow::{Borrow, BorrowMut};
use crate::cmp::Ordering;
use crate::convert::{Infallible, TryFrom};
+use crate::error::Error;
use crate::fmt;
use crate::hash::{self, Hash};
use crate::iter::TrustedLen;
@@ -31,6 +32,10 @@ pub use iter::IntoIter;
/// # Example
///
/// ```rust
+/// // type inference is helping us here, the way `from_fn` knows how many
+/// // elements to produce is the length of array down there: only arrays of
+/// // equal lengths can be compared, so the const generic parameter `N` is
+/// // inferred to be 5, thus creating array of 5 elements.
/// let array = core::array::from_fn(|i| i);
/// assert_eq!(array, [0, 1, 2, 3, 4]);
/// ```
@@ -119,6 +124,14 @@ impl fmt::Display for TryFromSliceError {
}
}
+#[stable(feature = "try_from", since = "1.34.0")]
+impl Error for TryFromSliceError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
impl TryFromSliceError {
#[unstable(
feature = "array_error_internals",
@@ -173,6 +186,18 @@ impl<T, const N: usize> const BorrowMut<[T]> for [T; N] {
}
}
+/// Tries to create an array `[T; N]` by copying from a slice `&[T]`. Succeeds if
+/// `slice.len() == N`.
+///
+/// ```
+/// let bytes: [u8; 3] = [1, 0, 2];
+///
+/// let bytes_head: [u8; 2] = <[u8; 2]>::try_from(&bytes[0..2]).unwrap();
+/// assert_eq!(1, u16::from_le_bytes(bytes_head));
+///
+/// let bytes_tail: [u8; 2] = bytes[1..3].try_into().unwrap();
+/// assert_eq!(512, u16::from_le_bytes(bytes_tail));
+/// ```
#[stable(feature = "try_from", since = "1.34.0")]
impl<T, const N: usize> TryFrom<&[T]> for [T; N]
where
@@ -185,6 +210,18 @@ where
}
}
+/// Tries to create an array `[T; N]` by copying from a mutable slice `&mut [T]`.
+/// Succeeds if `slice.len() == N`.
+///
+/// ```
+/// let mut bytes: [u8; 3] = [1, 0, 2];
+///
+/// let bytes_head: [u8; 2] = <[u8; 2]>::try_from(&mut bytes[0..2]).unwrap();
+/// assert_eq!(1, u16::from_le_bytes(bytes_head));
+///
+/// let bytes_tail: [u8; 2] = (&mut bytes[1..3]).try_into().unwrap();
+/// assert_eq!(512, u16::from_le_bytes(bytes_tail));
+/// ```
#[stable(feature = "try_from_mut_slice_to_array", since = "1.59.0")]
impl<T, const N: usize> TryFrom<&mut [T]> for [T; N]
where
@@ -197,6 +234,18 @@ where
}
}
+/// Tries to create an array ref `&[T; N]` from a slice ref `&[T]`. Succeeds if
+/// `slice.len() == N`.
+///
+/// ```
+/// let bytes: [u8; 3] = [1, 0, 2];
+///
+/// let bytes_head: &[u8; 2] = <&[u8; 2]>::try_from(&bytes[0..2]).unwrap();
+/// assert_eq!(1, u16::from_le_bytes(*bytes_head));
+///
+/// let bytes_tail: &[u8; 2] = bytes[1..3].try_into().unwrap();
+/// assert_eq!(512, u16::from_le_bytes(*bytes_tail));
+/// ```
#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] {
type Error = TryFromSliceError;
@@ -212,6 +261,18 @@ impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] {
}
}
+/// Tries to create a mutable array ref `&mut [T; N]` from a mutable slice ref
+/// `&mut [T]`. Succeeds if `slice.len() == N`.
+///
+/// ```
+/// let mut bytes: [u8; 3] = [1, 0, 2];
+///
+/// let bytes_head: &mut [u8; 2] = <&mut [u8; 2]>::try_from(&mut bytes[0..2]).unwrap();
+/// assert_eq!(1, u16::from_le_bytes(*bytes_head));
+///
+/// let bytes_tail: &mut [u8; 2] = (&mut bytes[1..3]).try_into().unwrap();
+/// assert_eq!(512, u16::from_le_bytes(*bytes_tail));
+/// ```
#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] {
type Error = TryFromSliceError;
@@ -375,7 +436,8 @@ impl<T: Copy> SpecArrayClone for T {
macro_rules! array_impl_default {
{$n:expr, $t:ident $($ts:ident)*} => {
#[stable(since = "1.4.0", feature = "array_default")]
- impl<T> Default for [T; $n] where T: Default {
+ #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+ impl<T> const Default for [T; $n] where T: ~const Default {
fn default() -> [T; $n] {
[$t::default(), $($ts::default()),*]
}
@@ -854,7 +916,7 @@ where
mem::forget(guard);
// SAFETY: All elements of the array were populated in the loop above.
- let output = unsafe { MaybeUninit::array_assume_init(array) };
+ let output = unsafe { array.transpose().assume_init() };
Ok(Try::from_output(output))
}
diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs
index f7a8aa0d9..db1c505ba 100644
--- a/library/core/src/bool.rs
+++ b/library/core/src/bool.rs
@@ -6,12 +6,30 @@ impl bool {
/// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html),
/// or `None` otherwise.
///
+ /// Arguments passed to `then_some` are eagerly evaluated; if you are
+ /// passing the result of a function call, it is recommended to use
+ /// [`then`], which is lazily evaluated.
+ ///
+ /// [`then`]: bool::then
+ ///
/// # Examples
///
/// ```
/// assert_eq!(false.then_some(0), None);
/// assert_eq!(true.then_some(0), Some(0));
/// ```
+ ///
+ /// ```
+ /// let mut a = 0;
+ /// let mut function_with_side_effects = || { a += 1; };
+ ///
+ /// true.then_some(function_with_side_effects());
+ /// false.then_some(function_with_side_effects());
+ ///
+ /// // `a` is incremented twice because the value passed to `then_some` is
+ /// // evaluated eagerly.
+ /// assert_eq!(a, 2);
+ /// ```
#[stable(feature = "bool_to_option", since = "1.62.0")]
#[rustc_const_unstable(feature = "const_bool_to_option", issue = "91917")]
#[inline]
@@ -31,6 +49,17 @@ impl bool {
/// assert_eq!(false.then(|| 0), None);
/// assert_eq!(true.then(|| 0), Some(0));
/// ```
+ ///
+ /// ```
+ /// let mut a = 0;
+ ///
+ /// true.then(|| { a += 1; });
+ /// false.then(|| { a += 1; });
+ ///
+ /// // `a` is incremented once because the closure is evaluated lazily by
+ /// // `then`.
+ /// assert_eq!(a, 1);
+ /// ```
#[stable(feature = "lazy_bool_to_option", since = "1.50.0")]
#[rustc_const_unstable(feature = "const_bool_to_option", issue = "91917")]
#[inline]
diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs
index 58eabecf3..fdd56cb4e 100644
--- a/library/core/src/borrow.rs
+++ b/library/core/src/borrow.rs
@@ -1,4 +1,4 @@
-//! A module for working with borrowed data.
+//! Utilities for working with borrowed data.
#![stable(feature = "rust1", since = "1.0.0")]
@@ -154,6 +154,7 @@
/// [`String`]: ../../std/string/struct.String.html
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Borrow"]
+#[const_trait]
pub trait Borrow<Borrowed: ?Sized> {
/// Immutably borrows from an owned value.
///
@@ -184,6 +185,7 @@ pub trait Borrow<Borrowed: ?Sized> {
/// an underlying type by providing a mutable reference. See [`Borrow<T>`]
/// for more information on borrowing as another type.
#[stable(feature = "rust1", since = "1.0.0")]
+#[const_trait]
pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
/// Mutably borrows from an owned value.
///
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index fb4454c94..7bf32cb0d 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -405,6 +405,7 @@ impl<T> Cell<T> {
/// assert_eq!(cell.replace(10), 5);
/// assert_eq!(cell.get(), 10);
/// ```
+ #[inline]
#[stable(feature = "move_cell", since = "1.17.0")]
pub fn replace(&self, val: T) -> T {
// SAFETY: This can cause data races if called from a separate thread,
@@ -614,6 +615,7 @@ impl<T, const N: usize> Cell<[T; N]> {
/// A mutable memory location with dynamically checked borrow rules
///
/// See the [module-level documentation](self) for more.
+#[cfg_attr(not(test), rustc_diagnostic_item = "RefCell")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RefCell<T: ?Sized> {
borrow: Cell<BorrowFlag>,
@@ -1021,15 +1023,18 @@ impl<T: ?Sized> RefCell<T> {
/// Returns a mutable reference to the underlying data.
///
- /// This call borrows `RefCell` mutably (at compile-time) so there is no
- /// need for dynamic checks.
+ /// Since this method borrows `RefCell` mutably, it is statically guaranteed
+ /// that no borrows to the underlying data exist. The dynamic checks inherent
+ /// in [`borrow_mut`] and most other methods of `RefCell` are therefor
+ /// unnecessary.
///
- /// However be cautious: this method expects `self` to be mutable, which is
- /// generally not the case when using a `RefCell`. Take a look at the
- /// [`borrow_mut`] method instead if `self` isn't mutable.
+ /// This method can only be called if `RefCell` can be mutably borrowed,
+ /// which in general is only the case directly after the `RefCell` has
+ /// been created. In these situations, skipping the aforementioned dynamic
+ /// borrowing checks may yield better ergonomics and runtime-performance.
///
- /// Also, please be aware that this method is only for special circumstances and is usually
- /// not what you want. In case of doubt, use [`borrow_mut`] instead.
+ /// In most situations where `RefCell` is used, it can't be borrowed mutably.
+ /// Use [`borrow_mut`] to get mutable access to the underlying data then.
///
/// [`borrow_mut`]: RefCell::borrow_mut()
///
@@ -1811,6 +1816,61 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
///
/// [`.get_mut()`]: `UnsafeCell::get_mut`
///
+/// # Memory layout
+///
+/// `UnsafeCell<T>` has the same in-memory representation as its inner type `T`. A consequence
+/// of this guarantee is that it is possible to convert between `T` and `UnsafeCell<T>`.
+/// Special care has to be taken when converting a nested `T` inside of an `Outer<T>` type
+/// to an `Outer<UnsafeCell<T>>` type: this is not sound when the `Outer<T>` type enables [niche]
+/// optimizations. For example, the type `Option<NonNull<u8>>` is typically 8 bytes large on
+/// 64-bit platforms, but the type `Option<UnsafeCell<NonNull<u8>>>` takes up 16 bytes of space.
+/// Therefore this is not a valid conversion, despite `NonNull<u8>` and `UnsafeCell<NonNull<u8>>>`
+/// having the same memory layout. This is because `UnsafeCell` disables niche optimizations in
+/// order to avoid its interior mutability property from spreading from `T` into the `Outer` type,
+/// thus this can cause distortions in the type size in these cases.
+///
+/// Note that the only valid way to obtain a `*mut T` pointer to the contents of a
+/// _shared_ `UnsafeCell<T>` is through [`.get()`] or [`.raw_get()`]. A `&mut T` reference
+/// can be obtained by either dereferencing this pointer or by calling [`.get_mut()`]
+/// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
+/// same memory layout, the following is not allowed and undefined behavior:
+///
+/// ```rust,no_run
+/// # use std::cell::UnsafeCell;
+/// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
+/// let t = ptr as *const UnsafeCell<T> as *mut T;
+/// // This is undefined behavior, because the `*mut T` pointer
+/// // was not obtained through `.get()` nor `.raw_get()`:
+/// unsafe { &mut *t }
+/// }
+/// ```
+///
+/// Instead, do this:
+///
+/// ```rust
+/// # use std::cell::UnsafeCell;
+/// // Safety: the caller must ensure that there are no references that
+/// // point to the *contents* of the `UnsafeCell`.
+/// unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
+/// unsafe { &mut *ptr.get() }
+/// }
+/// ```
+///
+/// Coverting in the other direction from a `&mut T`
+/// to an `&UnsafeCell<T>` is allowed:
+///
+/// ```rust
+/// # use std::cell::UnsafeCell;
+/// fn get_shared<T>(ptr: &mut T) -> &UnsafeCell<T> {
+/// let t = ptr as *mut T as *const UnsafeCell<T>;
+/// // SAFETY: `T` and `UnsafeCell<T>` have the same memory layout
+/// unsafe { &*t }
+/// }
+/// ```
+///
+/// [niche]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#niche
+/// [`.raw_get()`]: `UnsafeCell::raw_get`
+///
/// # Examples
///
/// Here is an example showcasing how to soundly mutate the contents of an `UnsafeCell<_>` despite
diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs
index 71297acd1..11f1c30f6 100644
--- a/library/core/src/char/decode.rs
+++ b/library/core/src/char/decode.rs
@@ -1,5 +1,6 @@
//! UTF-8 and UTF-16 decoding iterators
+use crate::error::Error;
use crate::fmt;
use super::from_u32_unchecked;
@@ -121,3 +122,11 @@ impl fmt::Display for DecodeUtf16Error {
write!(f, "unpaired surrogate found: {:x}", self.code)
}
}
+
+#[stable(feature = "decode_utf16", since = "1.9.0")]
+impl Error for DecodeUtf16Error {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "unpaired surrogate found"
+ }
+}
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index eae567cad..bb8359936 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -597,9 +597,14 @@ impl char {
/// Returns the number of 16-bit code units this `char` would need if
/// encoded in UTF-16.
///
+ /// That number of code units is always either 1 or 2, for unicode scalar values in
+ /// the [basic multilingual plane] or [supplementary planes] respectively.
+ ///
/// See the documentation for [`len_utf8()`] for more explanation of this
/// concept. This function is a mirror, but for UTF-16 instead of UTF-8.
///
+ /// [basic multilingual plane]: http://www.unicode.org/glossary/#basic_multilingual_plane
+ /// [supplementary planes]: http://www.unicode.org/glossary/#supplementary_planes
/// [`len_utf8()`]: #method.len_utf8
///
/// # Examples
@@ -746,10 +751,19 @@ impl char {
/// assert!(!'中'.is_lowercase());
/// assert!(!' '.is_lowercase());
/// ```
+ ///
+ /// In a const context:
+ ///
+ /// ```
+ /// #![feature(const_unicode_case_lookup)]
+ /// const CAPITAL_DELTA_IS_LOWERCASE: bool = 'Δ'.is_lowercase();
+ /// assert!(!CAPITAL_DELTA_IS_LOWERCASE);
+ /// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
#[inline]
- pub fn is_lowercase(self) -> bool {
+ pub const fn is_lowercase(self) -> bool {
match self {
'a'..='z' => true,
c => c > '\x7f' && unicode::Lowercase(c),
@@ -779,10 +793,19 @@ impl char {
/// assert!(!'中'.is_uppercase());
/// assert!(!' '.is_uppercase());
/// ```
+ ///
+ /// In a const context:
+ ///
+ /// ```
+ /// #![feature(const_unicode_case_lookup)]
+ /// const CAPITAL_DELTA_IS_UPPERCASE: bool = 'Δ'.is_uppercase();
+ /// assert!(CAPITAL_DELTA_IS_UPPERCASE);
+ /// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
#[inline]
- pub fn is_uppercase(self) -> bool {
+ pub const fn is_uppercase(self) -> bool {
match self {
'A'..='Z' => true,
c => c > '\x7f' && unicode::Uppercase(c),
@@ -892,8 +915,7 @@ impl char {
///
/// The general categories for numbers (`Nd` for decimal digits, `Nl` for letter-like numeric
/// characters, and `No` for other numeric characters) are specified in the [Unicode Character
- /// Database][ucd] [`UnicodeData.txt`]. Note that this means ideographic numbers like '三'
- /// are considered alphabetic, not numeric. Please consider to use `is_ascii_digit` or `is_digit`.
+ /// Database][ucd] [`UnicodeData.txt`].
///
/// This method doesn't cover everything that could be considered a number, e.g. ideographic numbers like '三'.
/// If you want everything including characters with overlapping purposes then you might want to use
@@ -1427,6 +1449,38 @@ impl char {
matches!(*self, '0'..='9')
}
+ /// Checks if the value is an ASCII octal digit:
+ /// U+0030 '0' ..= U+0037 '7'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(is_ascii_octdigit)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let a = 'a';
+ /// let zero = '0';
+ /// let seven = '7';
+ /// let nine = '9';
+ /// let percent = '%';
+ /// let lf = '\n';
+ ///
+ /// assert!(!uppercase_a.is_ascii_octdigit());
+ /// assert!(!a.is_ascii_octdigit());
+ /// assert!(zero.is_ascii_octdigit());
+ /// assert!(seven.is_ascii_octdigit());
+ /// assert!(!nine.is_ascii_octdigit());
+ /// assert!(!percent.is_ascii_octdigit());
+ /// assert!(!lf.is_ascii_octdigit());
+ /// ```
+ #[must_use]
+ #[unstable(feature = "is_ascii_octdigit", issue = "101288")]
+ #[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")]
+ #[inline]
+ pub const fn is_ascii_octdigit(&self) -> bool {
+ matches!(*self, '0'..='7')
+ }
+
/// Checks if the value is an ASCII hexadecimal digit:
///
/// - U+0030 '0' ..= U+0039 '9', or
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index 0df23e7bb..b34a71216 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -1,4 +1,6 @@
-//! A character type.
+//! Utilities for the `char` primitive type.
+//!
+//! *[See also the `char` primitive type](primitive@char).*
//!
//! The `char` type represents a single character. More specifically, since
//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
@@ -36,6 +38,7 @@ pub use self::methods::encode_utf16_raw;
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
pub use self::methods::encode_utf8_raw;
+use crate::error::Error;
use crate::fmt::{self, Write};
use crate::iter::FusedIterator;
@@ -582,3 +585,6 @@ impl fmt::Display for TryFromCharError {
"unicode code point out of range".fmt(fmt)
}
}
+
+#[stable(feature = "u8_from_char", since = "1.59.0")]
+impl Error for TryFromCharError {}
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 20bb67687..f0fa2e1d2 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -1,6 +1,6 @@
-//! Functionality for ordering and comparison.
+//! Utilities for comparing and ordering values.
//!
-//! This module contains various tools for ordering and comparing values. In
+//! This module contains various tools for comparing and ordering values. In
//! summary:
//!
//! * [`Eq`] and [`PartialEq`] are traits that allow you to define total and
@@ -22,7 +22,9 @@
#![stable(feature = "rust1", since = "1.0.0")]
+use crate::const_closure::ConstFnMutClosure;
use crate::marker::Destruct;
+use crate::marker::StructuralPartialEq;
use self::Ordering::*;
@@ -38,8 +40,10 @@ use self::Ordering::*;
///
/// Implementations must ensure that `eq` and `ne` are consistent with each other:
///
-/// - `a != b` if and only if `!(a == b)`
-/// (ensured by the default implementation).
+/// - `a != b` if and only if `!(a == b)`.
+///
+/// The default implementation of `ne` provides this consistency and is almost
+/// always sufficient. It should not be overridden without very good reason.
///
/// If [`PartialOrd`] or [`Ord`] are also implemented for `Self` and `Rhs`, their methods must also
/// be consistent with `PartialEq` (see the documentation of those traits for the exact
@@ -201,20 +205,10 @@ use self::Ordering::*;
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(alias = "==")]
#[doc(alias = "!=")]
-#[cfg_attr(
- bootstrap,
- rustc_on_unimplemented(
- message = "can't compare `{Self}` with `{Rhs}`",
- label = "no implementation for `{Self} == {Rhs}`"
- )
-)]
-#[cfg_attr(
- not(bootstrap),
- rustc_on_unimplemented(
- message = "can't compare `{Self}` with `{Rhs}`",
- label = "no implementation for `{Self} == {Rhs}`",
- append_const_msg,
- )
+#[rustc_on_unimplemented(
+ message = "can't compare `{Self}` with `{Rhs}`",
+ label = "no implementation for `{Self} == {Rhs}`",
+ append_const_msg
)]
#[const_trait]
#[rustc_diagnostic_item = "PartialEq"]
@@ -225,7 +219,8 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
#[stable(feature = "rust1", since = "1.0.0")]
fn eq(&self, other: &Rhs) -> bool;
- /// This method tests for `!=`.
+ /// This method tests for `!=`. The default implementation is almost always
+ /// sufficient, and should not be overridden without very good reason.
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -335,7 +330,7 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> {
/// let result = 2.cmp(&1);
/// assert_eq!(Ordering::Greater, result);
/// ```
-#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Copy, Eq, Debug, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
#[repr(i8)]
pub enum Ordering {
@@ -882,6 +877,18 @@ pub macro Ord($item:item) {
}
#[stable(feature = "rust1", since = "1.0.0")]
+impl StructuralPartialEq for Ordering {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+impl const PartialEq for Ordering {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ (*self as i32).eq(&(*other as i32))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl const Ord for Ordering {
#[inline]
@@ -1060,20 +1067,10 @@ impl const PartialOrd for Ordering {
#[doc(alias = "<")]
#[doc(alias = "<=")]
#[doc(alias = ">=")]
-#[cfg_attr(
- bootstrap,
- rustc_on_unimplemented(
- message = "can't compare `{Self}` with `{Rhs}`",
- label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
- )
-)]
-#[cfg_attr(
- not(bootstrap),
- rustc_on_unimplemented(
- message = "can't compare `{Self}` with `{Rhs}`",
- label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
- append_const_msg,
- )
+#[rustc_on_unimplemented(
+ message = "can't compare `{Self}` with `{Rhs}`",
+ label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
+ append_const_msg
)]
#[const_trait]
#[rustc_diagnostic_item = "PartialOrd"]
@@ -1139,11 +1136,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn le(&self, other: &Rhs) -> bool {
- // Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`.
- // FIXME: The root cause was fixed upstream in LLVM with:
- // https://github.com/llvm/llvm-project/commit/9bad7de9a3fb844f1ca2965f35d0c2a3d1e11775
- // Revert this workaround once support for LLVM 12 gets dropped.
- !matches!(self.partial_cmp(other), None | Some(Greater))
+ matches!(self.partial_cmp(other), Some(Less | Equal))
}
/// This method tests greater than (for `self` and `other`) and is used by the `>` operator.
@@ -1230,7 +1223,12 @@ pub const fn min<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+pub const fn min_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
+where
+ T: ~const Destruct,
+ F: ~const Destruct,
+{
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v1,
Ordering::Greater => v2,
@@ -1252,8 +1250,24 @@ pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
- min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+pub const fn min_by_key<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(v1: T, v2: T, mut f: F) -> T
+where
+ T: ~const Destruct,
+ F: ~const Destruct,
+ K: ~const Destruct,
+{
+ const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
+ f: &mut F,
+ (v1, v2): (&T, &T),
+ ) -> Ordering
+ where
+ T: ~const Destruct,
+ K: ~const Destruct,
+ {
+ f(v1).cmp(&f(v2))
+ }
+ min_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
}
/// Compares and returns the maximum of two values.
@@ -1294,7 +1308,12 @@ pub const fn max<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+pub const fn max_by<T, F: ~const FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T
+where
+ T: ~const Destruct,
+ F: ~const Destruct,
+{
match compare(&v1, &v2) {
Ordering::Less | Ordering::Equal => v2,
Ordering::Greater => v1,
@@ -1316,8 +1335,24 @@ pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
#[inline]
#[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
- max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+pub const fn max_by_key<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(v1: T, v2: T, mut f: F) -> T
+where
+ T: ~const Destruct,
+ F: ~const Destruct,
+ K: ~const Destruct,
+{
+ const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
+ f: &mut F,
+ (v1, v2): (&T, &T),
+ ) -> Ordering
+ where
+ T: ~const Destruct,
+ K: ~const Destruct,
+ {
+ f(v1).cmp(&f(v2))
+ }
+ max_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
}
// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
diff --git a/library/core/src/const_closure.rs b/library/core/src/const_closure.rs
new file mode 100644
index 000000000..9e9c02093
--- /dev/null
+++ b/library/core/src/const_closure.rs
@@ -0,0 +1,77 @@
+use crate::marker::Destruct;
+
+/// Struct representing a closure with mutably borrowed data.
+///
+/// Example:
+/// ```no_build
+/// #![feature(const_mut_refs)]
+/// use crate::const_closure::ConstFnMutClosure;
+/// const fn imp(state: &mut i32, (arg,): (i32,)) -> i32 {
+/// *state += arg;
+/// *state
+/// }
+/// let mut i = 5;
+/// let mut cl = ConstFnMutClosure::new(&mut i, imp);
+///
+/// assert!(7 == cl(2));
+/// assert!(8 == cl(1));
+/// ```
+pub(crate) struct ConstFnMutClosure<CapturedData, Function> {
+ /// The Data captured by the Closure.
+ /// Must be either a (mutable) reference or a tuple of (mutable) references.
+ pub data: CapturedData,
+ /// The Function of the Closure, must be: Fn(CapturedData, ClosureArgs) -> ClosureReturn
+ pub func: Function,
+}
+impl<'a, CapturedData: ?Sized, Function> ConstFnMutClosure<&'a mut CapturedData, Function> {
+ /// Function for creating a new closure.
+ ///
+ /// `data` is the a mutable borrow of data that is captured from the environment.
+ /// If you want Data to be a tuple of mutable Borrows, the struct must be constructed manually.
+ ///
+ /// `func` is the function of the closure, it gets the data and a tuple of the arguments closure
+ /// and return the return value of the closure.
+ pub(crate) const fn new<ClosureArguments, ClosureReturnValue>(
+ data: &'a mut CapturedData,
+ func: Function,
+ ) -> Self
+ where
+ Function: ~const Fn(&mut CapturedData, ClosureArguments) -> ClosureReturnValue,
+ {
+ Self { data, func }
+ }
+}
+
+macro_rules! impl_fn_mut_tuple {
+ ($($var:ident)*) => {
+ #[allow(unused_parens)]
+ impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
+ FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
+ where
+ Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue+ ~const Destruct,
+ {
+ type Output = ClosureReturnValue;
+
+ extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output {
+ self.call_mut(args)
+ }
+ }
+ #[allow(unused_parens)]
+ impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
+ FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
+ where
+ Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue,
+ {
+ extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
+ #[allow(non_snake_case)]
+ let ($($var),*) = &mut self.data;
+ (self.func)(($($var),*), args)
+ }
+ }
+ };
+}
+impl_fn_mut_tuple!(A);
+impl_fn_mut_tuple!(A B);
+impl_fn_mut_tuple!(A B C);
+impl_fn_mut_tuple!(A B C D);
+impl_fn_mut_tuple!(A B C D E);
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index b30c8a4ae..33493964b 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -25,6 +25,7 @@
//! # Generic Implementations
//!
//! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference
+//! (but not generally for all [dereferenceable types][core::ops::Deref])
//! - [`From`]`<U> for T` implies [`Into`]`<T> for U`
//! - [`TryFrom`]`<U> for T` implies [`TryInto`]`<T> for U`
//! - [`From`] and [`Into`] are reflexive, which means that all types can
@@ -34,6 +35,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
+use crate::error::Error;
use crate::fmt;
use crate::hash::{Hash, Hasher};
@@ -108,10 +110,12 @@ pub const fn identity<T>(x: T) -> T {
/// If you need to do a costly conversion it is better to implement [`From`] with type
/// `&T` or write a custom function.
///
+/// # Relation to `Borrow`
+///
/// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in a few aspects:
///
/// - Unlike `AsRef`, [`Borrow`] has a blanket impl for any `T`, and can be used to accept either
-/// a reference or a value.
+/// a reference or a value. (See also note on `AsRef`'s reflexibility below.)
/// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for a borrowed value are
/// equivalent to those of the owned value. For this reason, if you want to
/// borrow only a single field of a struct you can implement `AsRef`, but not [`Borrow`].
@@ -121,9 +125,66 @@ pub const fn identity<T>(x: T) -> T {
///
/// # Generic Implementations
///
-/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable
-/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type
-/// `&mut Foo` or `&&mut Foo`)
+/// `AsRef` auto-dereferences if the inner type is a reference or a mutable reference
+/// (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`).
+///
+/// Note that due to historic reasons, the above currently does not hold generally for all
+/// [dereferenceable types], e.g. `foo.as_ref()` will *not* work the same as
+/// `Box::new(foo).as_ref()`. Instead, many smart pointers provide an `as_ref` implementation which
+/// simply returns a reference to the [pointed-to value] (but do not perform a cheap
+/// reference-to-reference conversion for that value). However, [`AsRef::as_ref`] should not be
+/// used for the sole purpose of dereferencing; instead ['`Deref` coercion'] can be used:
+///
+/// [dereferenceable types]: core::ops::Deref
+/// [pointed-to value]: core::ops::Deref::Target
+/// ['`Deref` coercion']: core::ops::Deref#more-on-deref-coercion
+///
+/// ```
+/// let x = Box::new(5i32);
+/// // Avoid this:
+/// // let y: &i32 = x.as_ref();
+/// // Better just write:
+/// let y: &i32 = &x;
+/// ```
+///
+/// Types which implement [`Deref`] should consider implementing `AsRef<T>` as follows:
+///
+/// [`Deref`]: core::ops::Deref
+///
+/// ```
+/// # use core::ops::Deref;
+/// # struct SomeType;
+/// # impl Deref for SomeType {
+/// # type Target = [u8];
+/// # fn deref(&self) -> &[u8] {
+/// # &[]
+/// # }
+/// # }
+/// impl<T> AsRef<T> for SomeType
+/// where
+/// T: ?Sized,
+/// <SomeType as Deref>::Target: AsRef<T>,
+/// {
+/// fn as_ref(&self) -> &T {
+/// self.deref().as_ref()
+/// }
+/// }
+/// ```
+///
+/// # Reflexivity
+///
+/// Ideally, `AsRef` would be reflexive, i.e. there would be an `impl<T: ?Sized> AsRef<T> for T`
+/// with [`as_ref`] simply returning its argument unchanged.
+/// Such a blanket implementation is currently *not* provided due to technical restrictions of
+/// Rust's type system (it would be overlapping with another existing blanket implementation for
+/// `&T where T: AsRef<U>` which allows `AsRef` to auto-dereference, see "Generic Implementations"
+/// above).
+///
+/// [`as_ref`]: AsRef::as_ref
+///
+/// A trivial implementation of `AsRef<T> for T` must be added explicitly for a particular type `T`
+/// where needed or desired. Note, however, that not all types from `std` contain such an
+/// implementation, and those cannot be added by external code due to orphan rules.
///
/// # Examples
///
@@ -153,6 +214,7 @@ pub const fn identity<T>(x: T) -> T {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "AsRef")]
+#[const_trait]
pub trait AsRef<T: ?Sized> {
/// Converts this type into a shared reference of the (usually inferred) input type.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -170,31 +232,141 @@ pub trait AsRef<T: ?Sized> {
///
/// # Generic Implementations
///
-/// - `AsMut` auto-dereferences if the inner type is a mutable reference
-/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo`
-/// or `&mut &mut Foo`)
+/// `AsMut` auto-dereferences if the inner type is a mutable reference
+/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo` or `&mut &mut Foo`).
+///
+/// Note that due to historic reasons, the above currently does not hold generally for all
+/// [mutably dereferenceable types], e.g. `foo.as_mut()` will *not* work the same as
+/// `Box::new(foo).as_mut()`. Instead, many smart pointers provide an `as_mut` implementation which
+/// simply returns a reference to the [pointed-to value] (but do not perform a cheap
+/// reference-to-reference conversion for that value). However, [`AsMut::as_mut`] should not be
+/// used for the sole purpose of mutable dereferencing; instead ['`Deref` coercion'] can be used:
+///
+/// [mutably dereferenceable types]: core::ops::DerefMut
+/// [pointed-to value]: core::ops::Deref::Target
+/// ['`Deref` coercion']: core::ops::DerefMut#more-on-deref-coercion
+///
+/// ```
+/// let mut x = Box::new(5i32);
+/// // Avoid this:
+/// // let y: &mut i32 = x.as_mut();
+/// // Better just write:
+/// let y: &mut i32 = &mut x;
+/// ```
+///
+/// Types which implement [`DerefMut`] should consider to add an implementation of `AsMut<T>` as
+/// follows:
+///
+/// [`DerefMut`]: core::ops::DerefMut
+///
+/// ```
+/// # use core::ops::{Deref, DerefMut};
+/// # struct SomeType;
+/// # impl Deref for SomeType {
+/// # type Target = [u8];
+/// # fn deref(&self) -> &[u8] {
+/// # &[]
+/// # }
+/// # }
+/// # impl DerefMut for SomeType {
+/// # fn deref_mut(&mut self) -> &mut [u8] {
+/// # &mut []
+/// # }
+/// # }
+/// impl<T> AsMut<T> for SomeType
+/// where
+/// <SomeType as Deref>::Target: AsMut<T>,
+/// {
+/// fn as_mut(&mut self) -> &mut T {
+/// self.deref_mut().as_mut()
+/// }
+/// }
+/// ```
+///
+/// # Reflexivity
+///
+/// Ideally, `AsMut` would be reflexive, i.e. there would be an `impl<T: ?Sized> AsMut<T> for T`
+/// with [`as_mut`] simply returning its argument unchanged.
+/// Such a blanket implementation is currently *not* provided due to technical restrictions of
+/// Rust's type system (it would be overlapping with another existing blanket implementation for
+/// `&mut T where T: AsMut<U>` which allows `AsMut` to auto-dereference, see "Generic
+/// Implementations" above).
+///
+/// [`as_mut`]: AsMut::as_mut
+///
+/// A trivial implementation of `AsMut<T> for T` must be added explicitly for a particular type `T`
+/// where needed or desired. Note, however, that not all types from `std` contain such an
+/// implementation, and those cannot be added by external code due to orphan rules.
///
/// # Examples
///
-/// Using `AsMut` as trait bound for a generic function we can accept all mutable references
-/// that can be converted to type `&mut T`. Because [`Box<T>`] implements `AsMut<T>` we can
-/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`.
-/// Because [`Box<T>`] implements `AsMut<T>`, `add_one` accepts arguments of type
-/// `&mut Box<u64>` as well:
+/// Using `AsMut` as trait bound for a generic function, we can accept all mutable references that
+/// can be converted to type `&mut T`. Unlike [dereference], which has a single [target type],
+/// there can be multiple implementations of `AsMut` for a type. In particular, `Vec<T>` implements
+/// both `AsMut<Vec<T>>` and `AsMut<[T]>`.
+///
+/// In the following, the example functions `caesar` and `null_terminate` provide a generic
+/// interface which work with any type that can be converted by cheap mutable-to-mutable conversion
+/// into a byte slice (`[u8]`) or byte vector (`Vec<u8>`), respectively.
+///
+/// [dereference]: core::ops::DerefMut
+/// [target type]: core::ops::Deref::Target
///
/// ```
-/// fn add_one<T: AsMut<u64>>(num: &mut T) {
-/// *num.as_mut() += 1;
+/// struct Document {
+/// info: String,
+/// content: Vec<u8>,
+/// }
+///
+/// impl<T: ?Sized> AsMut<T> for Document
+/// where
+/// Vec<u8>: AsMut<T>,
+/// {
+/// fn as_mut(&mut self) -> &mut T {
+/// self.content.as_mut()
+/// }
/// }
///
-/// let mut boxed_num = Box::new(0);
-/// add_one(&mut boxed_num);
-/// assert_eq!(*boxed_num, 1);
+/// fn caesar<T: AsMut<[u8]>>(data: &mut T, key: u8) {
+/// for byte in data.as_mut() {
+/// *byte = byte.wrapping_add(key);
+/// }
+/// }
+///
+/// fn null_terminate<T: AsMut<Vec<u8>>>(data: &mut T) {
+/// // Using a non-generic inner function, which contains most of the
+/// // functionality, helps to minimize monomorphization overhead.
+/// fn doit(data: &mut Vec<u8>) {
+/// let len = data.len();
+/// if len == 0 || data[len-1] != 0 {
+/// data.push(0);
+/// }
+/// }
+/// doit(data.as_mut());
+/// }
+///
+/// fn main() {
+/// let mut v: Vec<u8> = vec![1, 2, 3];
+/// caesar(&mut v, 5);
+/// assert_eq!(v, [6, 7, 8]);
+/// null_terminate(&mut v);
+/// assert_eq!(v, [6, 7, 8, 0]);
+/// let mut doc = Document {
+/// info: String::from("Example"),
+/// content: vec![17, 19, 8],
+/// };
+/// caesar(&mut doc, 1);
+/// assert_eq!(doc.content, [18, 20, 9]);
+/// null_terminate(&mut doc);
+/// assert_eq!(doc.content, [18, 20, 9, 0]);
+/// }
/// ```
///
-/// [`Box<T>`]: ../../std/boxed/struct.Box.html
+/// Note, however, that APIs don't need to be generic. In many cases taking a `&mut [u8]` or
+/// `&mut Vec<u8>`, for example, is the better choice (callers need to pass the correct type then).
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")]
+#[const_trait]
pub trait AsMut<T: ?Sized> {
/// Converts this type into a mutable reference of the (usually inferred) input type.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -271,6 +443,7 @@ pub trait AsMut<T: ?Sized> {
/// [`Vec`]: ../../std/vec/struct.Vec.html
#[rustc_diagnostic_item = "Into"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[const_trait]
pub trait Into<T>: Sized {
/// Converts this type into the (usually inferred) input type.
#[must_use]
@@ -366,12 +539,13 @@ pub trait Into<T>: Sized {
all(_Self = "&str", T = "std::string::String"),
note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
))]
+#[const_trait]
pub trait From<T>: Sized {
/// Converts to this type from the input type.
#[lang = "from"]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
- fn from(_: T) -> Self;
+ fn from(value: T) -> Self;
}
/// An attempted conversion that consumes `self`, which may or may not be
@@ -390,6 +564,7 @@ pub trait From<T>: Sized {
/// [`Into`], see there for details.
#[rustc_diagnostic_item = "TryInto"]
#[stable(feature = "try_from", since = "1.34.0")]
+#[const_trait]
pub trait TryInto<T>: Sized {
/// The type returned in the event of a conversion error.
#[stable(feature = "try_from", since = "1.34.0")]
@@ -434,7 +609,7 @@ pub trait TryInto<T>: Sized {
///
/// fn try_from(value: i32) -> Result<Self, Self::Error> {
/// if value <= 0 {
-/// Err("GreaterThanZero only accepts value superior than zero!")
+/// Err("GreaterThanZero only accepts values greater than zero!")
/// } else {
/// Ok(GreaterThanZero(value))
/// }
@@ -466,6 +641,7 @@ pub trait TryInto<T>: Sized {
/// [`try_from`]: TryFrom::try_from
#[rustc_diagnostic_item = "TryFrom"]
#[stable(feature = "try_from", since = "1.34.0")]
+#[const_trait]
pub trait TryFrom<T>: Sized {
/// The type returned in the event of a conversion error.
#[stable(feature = "try_from", since = "1.34.0")]
@@ -556,6 +732,7 @@ where
#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const From<T> for T {
/// Returns the argument unchanged.
+ #[inline(always)]
fn from(t: T) -> T {
t
}
@@ -715,6 +892,13 @@ impl fmt::Display for Infallible {
}
}
+#[stable(feature = "str_parse_error2", since = "1.8.0")]
+impl Error for Infallible {
+ fn description(&self) -> &str {
+ match *self {}
+ }
+}
+
#[stable(feature = "convert_infallible", since = "1.34.0")]
impl PartialEq for Infallible {
fn eq(&self, _: &Infallible) -> bool {
diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index 1ce00828b..a5b4e9655 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -1,4 +1,4 @@
-//! The `Default` trait for types which may have meaningful default values.
+//! The `Default` trait for types with a default value.
#![stable(feature = "rust1", since = "1.0.0")]
@@ -99,6 +99,7 @@
/// ```
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), const_trait)]
pub trait Default: Sized {
/// Returns the "default value" for a type.
///
diff --git a/library/core/src/error.md b/library/core/src/error.md
new file mode 100644
index 000000000..891abebbf
--- /dev/null
+++ b/library/core/src/error.md
@@ -0,0 +1,137 @@
+Interfaces for working with Errors.
+
+# Error Handling In Rust
+
+The Rust language provides two complementary systems for constructing /
+representing, reporting, propagating, reacting to, and discarding errors.
+These responsibilities are collectively known as "error handling." The
+components of the first system, the panic runtime and interfaces, are most
+commonly used to represent bugs that have been detected in your program. The
+components of the second system, `Result`, the error traits, and user
+defined types, are used to represent anticipated runtime failure modes of
+your program.
+
+## The Panic Interfaces
+
+The following are the primary interfaces of the panic system and the
+responsibilities they cover:
+
+* [`panic!`] and [`panic_any`] (Constructing, Propagated automatically)
+* [`PanicInfo`] (Reporting)
+* [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting)
+* [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating)
+
+The following are the primary interfaces of the error system and the
+responsibilities they cover:
+
+* [`Result`] (Propagating, Reacting)
+* The [`Error`] trait (Reporting)
+* User defined types (Constructing / Representing)
+* [`match`] and [`downcast`] (Reacting)
+* The question mark operator ([`?`]) (Propagating)
+* The partially stable [`Try`] traits (Propagating, Constructing)
+* [`Termination`] (Reporting)
+
+## Converting Errors into Panics
+
+The panic and error systems are not entirely distinct. Often times errors
+that are anticipated runtime failures in an API might instead represent bugs
+to a caller. For these situations the standard library provides APIs for
+constructing panics with an `Error` as it's source.
+
+* [`Result::unwrap`]
+* [`Result::expect`]
+
+These functions are equivalent, they either return the inner value if the
+`Result` is `Ok` or panic if the `Result` is `Err` printing the inner error
+as the source. The only difference between them is that with `expect` you
+provide a panic error message to be printed alongside the source, whereas
+`unwrap` has a default message indicating only that you unwraped an `Err`.
+
+Of the two, `expect` is generally preferred since its `msg` field allows you
+to convey your intent and assumptions which makes tracking down the source
+of a panic easier. `unwrap` on the other hand can still be a good fit in
+situations where you can trivially show that a piece of code will never
+panic, such as `"127.0.0.1".parse::<std::net::IpAddr>().unwrap()` or early
+prototyping.
+
+# Common Message Styles
+
+There are two common styles for how people word `expect` messages. Using
+the message to present information to users encountering a panic
+("expect as error message") or using the message to present information
+to developers debugging the panic ("expect as precondition").
+
+In the former case the expect message is used to describe the error that
+has occurred which is considered a bug. Consider the following example:
+
+```should_panic
+// Read environment variable, panic if it is not present
+let path = std::env::var("IMPORTANT_PATH").unwrap();
+```
+
+In the "expect as error message" style we would use expect to describe
+that the environment variable was not set when it should have been:
+
+```should_panic
+let path = std::env::var("IMPORTANT_PATH")
+ .expect("env variable `IMPORTANT_PATH` is not set");
+```
+
+In the "expect as precondition" style, we would instead describe the
+reason we _expect_ the `Result` should be `Ok`. With this style we would
+prefer to write:
+
+```should_panic
+let path = std::env::var("IMPORTANT_PATH")
+ .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`");
+```
+
+The "expect as error message" style does not work as well with the
+default output of the std panic hooks, and often ends up repeating
+information that is already communicated by the source error being
+unwrapped:
+
+```text
+thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6
+```
+
+In this example we end up mentioning that an env variable is not set,
+followed by our source message that says the env is not present, the
+only additional information we're communicating is the name of the
+environment variable being checked.
+
+The "expect as precondition" style instead focuses on source code
+readability, making it easier to understand what must have gone wrong in
+situations where panics are being used to represent bugs exclusively.
+Also, by framing our expect in terms of what "SHOULD" have happened to
+prevent the source error, we end up introducing new information that is
+independent from our source error.
+
+```text
+thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6
+```
+
+In this example we are communicating not only the name of the
+environment variable that should have been set, but also an explanation
+for why it should have been set, and we let the source error display as
+a clear contradiction to our expectation.
+
+**Hint**: If you're having trouble remembering how to phrase
+expect-as-precondition style error messages remember to focus on the word
+"should" as in "env variable should be set by blah" or "the given binary
+should be available and executable by the current user".
+
+[`panic_any`]: ../../std/panic/fn.panic_any.html
+[`PanicInfo`]: crate::panic::PanicInfo
+[`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
+[`resume_unwind`]: ../../std/panic/fn.resume_unwind.html
+[`downcast`]: crate::error::Error
+[`Termination`]: ../../std/process/trait.Termination.html
+[`Try`]: crate::ops::Try
+[panic hook]: ../../std/panic/fn.set_hook.html
+[`set_hook`]: ../../std/panic/fn.set_hook.html
+[`take_hook`]: ../../std/panic/fn.take_hook.html
+[panic-handler]: <https://doc.rust-lang.org/nomicon/panic-handler.html>
+[`match`]: ../../std/keyword.match.html
+[`?`]: ../../std/result/index.html#the-question-mark-operator-
diff --git a/library/core/src/error.rs b/library/core/src/error.rs
new file mode 100644
index 000000000..2738b4994
--- /dev/null
+++ b/library/core/src/error.rs
@@ -0,0 +1,508 @@
+#![doc = include_str!("error.md")]
+#![unstable(feature = "error_in_core", issue = "none")]
+
+#[cfg(test)]
+mod tests;
+
+use crate::any::{Demand, Provider, TypeId};
+use crate::fmt::{Debug, Display};
+
+/// `Error` is a trait representing the basic expectations for error values,
+/// i.e., values of type `E` in [`Result<T, E>`].
+///
+/// Errors must describe themselves through the [`Display`] and [`Debug`]
+/// traits. Error messages are typically concise lowercase sentences without
+/// trailing punctuation:
+///
+/// ```
+/// let err = "NaN".parse::<u32>().unwrap_err();
+/// assert_eq!(err.to_string(), "invalid digit found in string");
+/// ```
+///
+/// Errors may provide cause information. [`Error::source()`] is generally
+/// used when errors cross "abstraction boundaries". If one module must report
+/// an error that is caused by an error from a lower-level module, it can allow
+/// accessing that error via [`Error::source()`]. This makes it possible for the
+/// high-level module to provide its own errors while also revealing some of the
+/// implementation for debugging.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
+#[rustc_has_incoherent_inherent_impls]
+pub trait Error: Debug + Display {
+ /// The lower-level source of this error, if any.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperError {
+ /// source: SuperErrorSideKick,
+ /// }
+ ///
+ /// impl fmt::Display for SuperError {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "SuperError is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperError {
+ /// fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// Some(&self.source)
+ /// }
+ /// }
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperErrorSideKick;
+ ///
+ /// impl fmt::Display for SuperErrorSideKick {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "SuperErrorSideKick is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperErrorSideKick {}
+ ///
+ /// fn get_super_error() -> Result<(), SuperError> {
+ /// Err(SuperError { source: SuperErrorSideKick })
+ /// }
+ ///
+ /// fn main() {
+ /// match get_super_error() {
+ /// Err(e) => {
+ /// println!("Error: {e}");
+ /// println!("Caused by: {}", e.source().unwrap());
+ /// }
+ /// _ => println!("No error"),
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "error_source", since = "1.30.0")]
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ None
+ }
+
+ /// Gets the `TypeId` of `self`.
+ #[doc(hidden)]
+ #[unstable(
+ feature = "error_type_id",
+ reason = "this is memory-unsafe to override in user code",
+ issue = "60784"
+ )]
+ fn type_id(&self, _: private::Internal) -> TypeId
+ where
+ Self: 'static,
+ {
+ TypeId::of::<Self>()
+ }
+
+ /// ```
+ /// if let Err(e) = "xc".parse::<u32>() {
+ /// // Print `e` itself, no need for description().
+ /// eprintln!("Error: {e}");
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[deprecated(since = "1.42.0", note = "use the Display impl or to_string()")]
+ fn description(&self) -> &str {
+ "description() is deprecated; use Display"
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[deprecated(
+ since = "1.33.0",
+ note = "replaced by Error::source, which can support downcasting"
+ )]
+ #[allow(missing_docs)]
+ fn cause(&self) -> Option<&dyn Error> {
+ self.source()
+ }
+
+ /// Provides type based access to context intended for error reports.
+ ///
+ /// Used in conjunction with [`Demand::provide_value`] and [`Demand::provide_ref`] to extract
+ /// references to member variables from `dyn Error` trait objects.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ /// #![feature(error_generic_member_access)]
+ /// use core::fmt;
+ /// use core::any::Demand;
+ ///
+ /// #[derive(Debug)]
+ /// struct MyBacktrace {
+ /// // ...
+ /// }
+ ///
+ /// impl MyBacktrace {
+ /// fn new() -> MyBacktrace {
+ /// // ...
+ /// # MyBacktrace {}
+ /// }
+ /// }
+ ///
+ /// #[derive(Debug)]
+ /// struct SourceError {
+ /// // ...
+ /// }
+ ///
+ /// impl fmt::Display for SourceError {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "Example Source Error")
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for SourceError {}
+ ///
+ /// #[derive(Debug)]
+ /// struct Error {
+ /// source: SourceError,
+ /// backtrace: MyBacktrace,
+ /// }
+ ///
+ /// impl fmt::Display for Error {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "Example Error")
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for Error {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// demand
+ /// .provide_ref::<MyBacktrace>(&self.backtrace)
+ /// .provide_ref::<dyn std::error::Error + 'static>(&self.source);
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let backtrace = MyBacktrace::new();
+ /// let source = SourceError {};
+ /// let error = Error { source, backtrace };
+ /// let dyn_error = &error as &dyn std::error::Error;
+ /// let backtrace_ref = dyn_error.request_ref::<MyBacktrace>().unwrap();
+ ///
+ /// assert!(core::ptr::eq(&error.backtrace, backtrace_ref));
+ /// }
+ /// ```
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ #[allow(unused_variables)]
+ fn provide<'a>(&'a self, demand: &mut Demand<'a>) {}
+}
+
+#[unstable(feature = "error_generic_member_access", issue = "99301")]
+impl<E> Provider for E
+where
+ E: Error + ?Sized,
+{
+ fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ self.provide(demand)
+ }
+}
+
+mod private {
+ // This is a hack to prevent `type_id` from being overridden by `Error`
+ // implementations, since that can enable unsound downcasting.
+ #[unstable(feature = "error_type_id", issue = "60784")]
+ #[derive(Debug)]
+ pub struct Internal;
+}
+
+#[unstable(feature = "never_type", issue = "35121")]
+impl Error for ! {}
+
+impl<'a> dyn Error + 'a {
+ /// Request a reference of type `T` as context about this error.
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ pub fn request_ref<T: ?Sized + 'static>(&'a self) -> Option<&'a T> {
+ core::any::request_ref(self)
+ }
+
+ /// Request a value of type `T` as context about this error.
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ pub fn request_value<T: 'static>(&'a self) -> Option<T> {
+ core::any::request_value(self)
+ }
+}
+
+// Copied from `any.rs`.
+impl dyn Error + 'static {
+ /// Returns `true` if the inner type is the same as `T`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn is<T: Error + 'static>(&self) -> bool {
+ // Get `TypeId` of the type this function is instantiated with.
+ let t = TypeId::of::<T>();
+
+ // Get `TypeId` of the type in the trait object (`self`).
+ let concrete = self.type_id(private::Internal);
+
+ // Compare both `TypeId`s on equality.
+ t == concrete
+ }
+
+ /// Returns some reference to the inner value if it is of type `T`, or
+ /// `None` if it isn't.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
+ if self.is::<T>() {
+ // SAFETY: `is` ensures this type cast is correct
+ unsafe { Some(&*(self as *const dyn Error as *const T)) }
+ } else {
+ None
+ }
+ }
+
+ /// Returns some mutable reference to the inner value if it is of type `T`, or
+ /// `None` if it isn't.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
+ if self.is::<T>() {
+ // SAFETY: `is` ensures this type cast is correct
+ unsafe { Some(&mut *(self as *mut dyn Error as *mut T)) }
+ } else {
+ None
+ }
+ }
+}
+
+impl dyn Error + 'static + Send {
+ /// Forwards to the method defined on the type `dyn Error`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn is<T: Error + 'static>(&self) -> bool {
+ <dyn Error + 'static>::is::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `dyn Error`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
+ <dyn Error + 'static>::downcast_ref::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `dyn Error`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
+ <dyn Error + 'static>::downcast_mut::<T>(self)
+ }
+
+ /// Request a reference of type `T` as context about this error.
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
+ <dyn Error>::request_ref(self)
+ }
+
+ /// Request a value of type `T` as context about this error.
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ pub fn request_value<T: 'static>(&self) -> Option<T> {
+ <dyn Error>::request_value(self)
+ }
+}
+
+impl dyn Error + 'static + Send + Sync {
+ /// Forwards to the method defined on the type `dyn Error`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn is<T: Error + 'static>(&self) -> bool {
+ <dyn Error + 'static>::is::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `dyn Error`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
+ <dyn Error + 'static>::downcast_ref::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `dyn Error`.
+ #[stable(feature = "error_downcast", since = "1.3.0")]
+ #[inline]
+ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
+ <dyn Error + 'static>::downcast_mut::<T>(self)
+ }
+
+ /// Request a reference of type `T` as context about this error.
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
+ <dyn Error>::request_ref(self)
+ }
+
+ /// Request a value of type `T` as context about this error.
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ pub fn request_value<T: 'static>(&self) -> Option<T> {
+ <dyn Error>::request_value(self)
+ }
+}
+
+impl dyn Error {
+ /// Returns an iterator starting with the current error and continuing with
+ /// recursively calling [`Error::source`].
+ ///
+ /// If you want to omit the current error and only use its sources,
+ /// use `skip(1)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(error_iter)]
+ /// use std::error::Error;
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// struct A;
+ ///
+ /// #[derive(Debug)]
+ /// struct B(Option<Box<dyn Error + 'static>>);
+ ///
+ /// impl fmt::Display for A {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "A")
+ /// }
+ /// }
+ ///
+ /// impl fmt::Display for B {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// write!(f, "B")
+ /// }
+ /// }
+ ///
+ /// impl Error for A {}
+ ///
+ /// impl Error for B {
+ /// fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// self.0.as_ref().map(|e| e.as_ref())
+ /// }
+ /// }
+ ///
+ /// let b = B(Some(Box::new(A)));
+ ///
+ /// // let err : Box<Error> = b.into(); // or
+ /// let err = &b as &(dyn Error);
+ ///
+ /// let mut iter = err.sources();
+ ///
+ /// assert_eq!("B".to_string(), iter.next().unwrap().to_string());
+ /// assert_eq!("A".to_string(), iter.next().unwrap().to_string());
+ /// assert!(iter.next().is_none());
+ /// assert!(iter.next().is_none());
+ /// ```
+ #[unstable(feature = "error_iter", issue = "58520")]
+ #[inline]
+ pub fn sources(&self) -> Source<'_> {
+ // You may think this method would be better in the Error trait, and you'd be right.
+ // Unfortunately that doesn't work, not because of the object safety rules but because we
+ // save a reference to self in Sources below as a trait object. If this method was
+ // declared in Error, then self would have the type &T where T is some concrete type which
+ // implements Error. We would need to coerce self to have type &dyn Error, but that requires
+ // that Self has a known size (i.e., Self: Sized). We can't put that bound on Error
+ // since that would forbid Error trait objects, and we can't put that bound on the method
+ // because that means the method can't be called on trait objects (we'd also need the
+ // 'static bound, but that isn't allowed because methods with bounds on Self other than
+ // Sized are not object-safe). Requiring an Unsize bound is not backwards compatible.
+
+ Source { current: Some(self) }
+ }
+}
+
+/// An iterator over an [`Error`] and its sources.
+///
+/// If you want to omit the initial error and only process
+/// its sources, use `skip(1)`.
+#[unstable(feature = "error_iter", issue = "58520")]
+#[derive(Clone, Debug)]
+pub struct Source<'a> {
+ current: Option<&'a (dyn Error + 'static)>,
+}
+
+#[unstable(feature = "error_iter", issue = "58520")]
+impl<'a> Iterator for Source<'a> {
+ type Item = &'a (dyn Error + 'static);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let current = self.current;
+ self.current = self.current.and_then(Error::source);
+ current
+ }
+}
+
+#[stable(feature = "error_by_ref", since = "1.51.0")]
+impl<'a, T: Error + ?Sized> Error for &'a T {
+ #[allow(deprecated, deprecated_in_future)]
+ fn description(&self) -> &str {
+ Error::description(&**self)
+ }
+
+ #[allow(deprecated)]
+ fn cause(&self) -> Option<&dyn Error> {
+ Error::cause(&**self)
+ }
+
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ Error::source(&**self)
+ }
+
+ fn provide<'b>(&'b self, demand: &mut Demand<'b>) {
+ Error::provide(&**self, demand);
+ }
+}
+
+#[stable(feature = "fmt_error", since = "1.11.0")]
+impl Error for crate::fmt::Error {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "an error occurred when formatting an argument"
+ }
+}
+
+#[stable(feature = "try_borrow", since = "1.13.0")]
+impl Error for crate::cell::BorrowError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "already mutably borrowed"
+ }
+}
+
+#[stable(feature = "try_borrow", since = "1.13.0")]
+impl Error for crate::cell::BorrowMutError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "already borrowed"
+ }
+}
+
+#[stable(feature = "try_from", since = "1.34.0")]
+impl Error for crate::char::CharTryFromError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "converted integer out of range for `char`"
+ }
+}
+
+#[stable(feature = "char_from_str", since = "1.20.0")]
+impl Error for crate::char::ParseCharError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[stable(feature = "duration_checked_float", since = "1.66.0")]
+impl Error for crate::time::TryFromFloatSecsError {}
+
+#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
+impl Error for crate::ffi::FromBytesWithNulError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+impl Error for crate::ffi::FromBytesUntilNulError {}
diff --git a/library/core/src/ffi/c_double.md b/library/core/src/ffi/c_double.md
index 57f453482..d49e29b6e 100644
--- a/library/core/src/ffi/c_double.md
+++ b/library/core/src/ffi/c_double.md
@@ -1,6 +1,6 @@
Equivalent to C's `double` type.
-This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard.
+This type will almost always be [`f64`], which is guaranteed to be an [IEEE 754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard.
-[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[IEEE 754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754
[`float`]: c_float
diff --git a/library/core/src/ffi/c_float.md b/library/core/src/ffi/c_float.md
index 61e2abc05..36374ef43 100644
--- a/library/core/src/ffi/c_float.md
+++ b/library/core/src/ffi/c_float.md
@@ -1,5 +1,5 @@
Equivalent to C's `float` type.
-This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all.
+This type will almost always be [`f32`], which is guaranteed to be an [IEEE 754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all.
-[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[IEEE 754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 82e63a7fe..8923f548a 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -1,7 +1,6 @@
-use crate::ascii;
use crate::cmp::Ordering;
use crate::ffi::c_char;
-use crate::fmt::{self, Write};
+use crate::fmt;
use crate::intrinsics;
use crate::ops;
use crate::slice;
@@ -121,10 +120,10 @@ enum FromBytesWithNulErrorKind {
}
impl FromBytesWithNulError {
- fn interior_nul(pos: usize) -> FromBytesWithNulError {
+ const fn interior_nul(pos: usize) -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
}
- fn not_nul_terminated() -> FromBytesWithNulError {
+ const fn not_nul_terminated() -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
}
@@ -161,11 +160,7 @@ impl fmt::Display for FromBytesUntilNulError {
#[stable(feature = "cstr_debug", since = "1.3.0")]
impl fmt::Debug for CStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "\"")?;
- for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
- f.write_char(byte as char)?;
- }
- write!(f, "\"")
+ write!(f, "\"{}\"", self.to_bytes().escape_ascii())
}
}
@@ -226,9 +221,7 @@ impl CStr {
/// # Examples
///
/// ```ignore (extern-declaration)
- /// # fn main() {
- /// use std::ffi::CStr;
- /// use std::os::raw::c_char;
+ /// use std::ffi::{c_char, CStr};
///
/// extern "C" {
/// fn my_string() -> *const c_char;
@@ -238,14 +231,26 @@ impl CStr {
/// let slice = CStr::from_ptr(my_string());
/// println!("string returned: {}", slice.to_str().unwrap());
/// }
- /// # }
+ /// ```
+ ///
+ /// ```
+ /// #![feature(const_cstr_methods)]
+ ///
+ /// use std::ffi::{c_char, CStr};
+ ///
+ /// const HELLO_PTR: *const c_char = {
+ /// const BYTES: &[u8] = b"Hello, world!\0";
+ /// BYTES.as_ptr().cast()
+ /// };
+ /// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) };
/// ```
///
/// [valid]: core::ptr#safety
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
// SAFETY: The caller has provided a pointer that points to a valid C
// string with a NUL terminator of size less than `isize::MAX`, whose
// content remain valid and doesn't change for the lifetime of the
@@ -257,13 +262,29 @@ impl CStr {
//
// The cast from c_char to u8 is ok because a c_char is always one byte.
unsafe {
- extern "C" {
- /// Provided by libc or compiler_builtins.
- fn strlen(s: *const c_char) -> usize;
+ const fn strlen_ct(s: *const c_char) -> usize {
+ let mut len = 0;
+
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
+ while unsafe { *s.add(len) } != 0 {
+ len += 1;
+ }
+
+ len
}
- let len = strlen(ptr);
- let ptr = ptr as *const u8;
- CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+
+ fn strlen_rt(s: *const c_char) -> usize {
+ extern "C" {
+ /// Provided by libc or compiler_builtins.
+ fn strlen(s: *const c_char) -> usize;
+ }
+
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
+ unsafe { strlen(s) }
+ }
+
+ let len = intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt);
+ Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1))
}
}
@@ -299,7 +320,8 @@ impl CStr {
/// ```
///
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
- pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
+ #[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+ pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
Some(nul_pos) => {
@@ -348,7 +370,8 @@ impl CStr {
/// assert!(cstr.is_err());
/// ```
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
- pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
Some(nul_pos) if nul_pos + 1 == bytes.len() => {
@@ -387,6 +410,7 @@ impl CStr {
#[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
#[rustc_allow_const_fn_unstable(const_eval_select)]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+ #[inline]
fn rt_impl(bytes: &[u8]) -> &CStr {
// Chance at catching some UB at runtime with debug builds.
debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
@@ -476,6 +500,34 @@ impl CStr {
self.inner.as_ptr()
}
+ /// Returns `true` if `self.to_bytes()` has a length of 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(cstr_is_empty)]
+ ///
+ /// use std::ffi::CStr;
+ /// # use std::ffi::FromBytesWithNulError;
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Result<(), FromBytesWithNulError> {
+ /// let cstr = CStr::from_bytes_with_nul(b"foo\0")?;
+ /// assert!(!cstr.is_empty());
+ ///
+ /// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?;
+ /// assert!(empty_cstr.is_empty());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[inline]
+ #[unstable(feature = "cstr_is_empty", issue = "102444")]
+ pub const fn is_empty(&self) -> bool {
+ // SAFETY: We know there is at least one byte; for empty strings it
+ // is the NUL terminator.
+ (unsafe { self.inner.get_unchecked(0) }) == &0
+ }
+
/// Converts this C string to a byte slice.
///
/// The returned slice will **not** contain the trailing nul terminator that this C
@@ -497,7 +549,8 @@ impl CStr {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn to_bytes(&self) -> &[u8] {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
// SAFETY: to_bytes_with_nul returns slice with length at least 1
unsafe { bytes.get_unchecked(..bytes.len() - 1) }
@@ -524,7 +577,8 @@ impl CStr {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn to_bytes_with_nul(&self) -> &[u8] {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const fn to_bytes_with_nul(&self) -> &[u8] {
// SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s
// is safe on all supported targets.
unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
@@ -547,7 +601,8 @@ impl CStr {
/// assert_eq!(cstr.to_str(), Ok("foo"));
/// ```
#[stable(feature = "cstr_to_str", since = "1.4.0")]
- pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const fn to_str(&self) -> Result<&str, str::Utf8Error> {
// N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
// instead of in `from_ptr()`, it may be worth considering if this should
// be rewritten to do the UTF-8 check inline with the length calculation
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs
index 32d1a4e55..7da49b04a 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -28,24 +28,14 @@ impl<'buf, 'state> PadAdapter<'buf, 'state> {
}
impl fmt::Write for PadAdapter<'_, '_> {
- fn write_str(&mut self, mut s: &str) -> fmt::Result {
- while !s.is_empty() {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ for s in s.split_inclusive('\n') {
if self.state.on_newline {
self.buf.write_str(" ")?;
}
- let split = match s.find('\n') {
- Some(pos) => {
- self.state.on_newline = true;
- pos + 1
- }
- None => {
- self.state.on_newline = false;
- s.len()
- }
- };
- self.buf.write_str(&s[..split])?;
- s = &s[split..];
+ self.state.on_newline = s.ends_with('\n');
+ self.buf.write_str(s)?;
}
Ok(())
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 372141e09..c8d285505 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -119,6 +119,10 @@ pub trait Write {
///
/// This function will return an instance of [`Error`] on error.
///
+ /// The purpose of std::fmt::Error is to abort the formatting operation when the underlying
+ /// destination encounters some error preventing it from accepting more text; it should
+ /// generally be propagated rather than handled, at least when implementing formatting traits.
+ ///
/// # Examples
///
/// ```
@@ -705,12 +709,19 @@ pub use macros::Debug;
/// Format trait for an empty format, `{}`.
///
+/// Implementing this trait for a type will automatically implement the
+/// [`ToString`][tostring] trait for the type, allowing the usage
+/// of the [`.to_string()`][tostring_function] method. Prefer implementing
+/// the `Display` trait for a type, rather than [`ToString`][tostring].
+///
/// `Display` is similar to [`Debug`], but `Display` is for user-facing
/// output, and so cannot be derived.
///
/// For more information on formatters, see [the module-level documentation][module].
///
/// [module]: ../../std/fmt/index.html
+/// [tostring]: ../../std/string/trait.ToString.html
+/// [tostring_function]: ../../std/string/trait.ToString.html#tymethod.to_string
///
/// # Examples
///
@@ -1815,7 +1826,7 @@ impl<'a> Formatter<'a> {
/// write!(formatter,
/// "Foo({}{})",
/// if self.0 < 0 { '-' } else { '+' },
- /// self.0)
+ /// self.0.abs())
/// } else {
/// write!(formatter, "Foo({})", self.0)
/// }
@@ -1823,6 +1834,7 @@ impl<'a> Formatter<'a> {
/// }
///
/// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)");
+ /// assert_eq!(&format!("{:+}", Foo(-23)), "Foo(-23)");
/// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
/// ```
#[must_use]
@@ -2562,7 +2574,7 @@ macro_rules! tuple {
macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
- #[cfg_attr(not(bootstrap), doc(fake_variadic))]
+ #[doc(fake_variadic)]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
@@ -2598,7 +2610,7 @@ impl Debug for () {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Debug for PhantomData<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
- f.debug_struct("PhantomData").finish()
+ write!(f, "PhantomData<{}>", crate::any::type_name::<T>())
}
}
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index 25789d37c..d8365ae9b 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -211,7 +211,7 @@ macro_rules! impl_Display {
fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// 2^128 is about 3*10^38, so 39 gives an extra byte of space
let mut buf = [MaybeUninit::<u8>::uninit(); 39];
- let mut curr = buf.len() as isize;
+ let mut curr = buf.len();
let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
@@ -228,7 +228,7 @@ macro_rules! impl_Display {
// eagerly decode 4 characters at a time
while n >= 10000 {
- let rem = (n % 10000) as isize;
+ let rem = (n % 10000) as usize;
n /= 10000;
let d1 = (rem / 100) << 1;
@@ -238,29 +238,29 @@ macro_rules! impl_Display {
// We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
// otherwise `curr < 0`. But then `n` was originally at least `10000^10`
// which is `10^40 > 2^128 > n`.
- ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(curr + 2), 2);
}
// if we reach here numbers are <= 9999, so at most 4 chars long
- let mut n = n as isize; // possibly reduce 64bit math
+ let mut n = n as usize; // possibly reduce 64bit math
// decode 2 more chars, if > 2 chars
if n >= 100 {
let d1 = (n % 100) << 1;
n /= 100;
curr -= 2;
- ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
}
// decode last 1 or 2 chars
if n < 10 {
curr -= 1;
- *buf_ptr.offset(curr) = (n as u8) + b'0';
+ *buf_ptr.add(curr) = (n as u8) + b'0';
} else {
let d1 = n << 1;
curr -= 2;
- ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
}
}
@@ -268,7 +268,7 @@ macro_rules! impl_Display {
// UTF-8 since `DEC_DIGITS_LUT` is
let buf_slice = unsafe {
str::from_utf8_unchecked(
- slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize))
+ slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
};
f.pad_integral(is_nonnegative, "", buf_slice)
}
@@ -339,18 +339,18 @@ macro_rules! impl_Exp {
// Since `curr` always decreases by the number of digits copied, this means
// that `curr >= 0`.
let mut buf = [MaybeUninit::<u8>::uninit(); 40];
- let mut curr = buf.len() as isize; //index for buf
+ let mut curr = buf.len(); //index for buf
let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
// decode 2 chars at a time
while n >= 100 {
- let d1 = ((n % 100) as isize) << 1;
+ let d1 = ((n % 100) as usize) << 1;
curr -= 2;
// SAFETY: `d1 <= 198`, so we can copy from `lut_ptr[d1..d1 + 2]` since
// `DEC_DIGITS_LUT` has a length of 200.
unsafe {
- ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
}
n /= 100;
exponent += 2;
@@ -362,7 +362,7 @@ macro_rules! impl_Exp {
curr -= 1;
// SAFETY: Safe since `40 > curr >= 0` (see comment)
unsafe {
- *buf_ptr.offset(curr) = (n as u8 % 10_u8) + b'0';
+ *buf_ptr.add(curr) = (n as u8 % 10_u8) + b'0';
}
n /= 10;
exponent += 1;
@@ -372,7 +372,7 @@ macro_rules! impl_Exp {
curr -= 1;
// SAFETY: Safe since `40 > curr >= 0`
unsafe {
- *buf_ptr.offset(curr) = b'.';
+ *buf_ptr.add(curr) = b'.';
}
}
@@ -380,10 +380,10 @@ macro_rules! impl_Exp {
let buf_slice = unsafe {
// decode last character
curr -= 1;
- *buf_ptr.offset(curr) = (n as u8) + b'0';
+ *buf_ptr.add(curr) = (n as u8) + b'0';
let len = buf.len() - curr as usize;
- slice::from_raw_parts(buf_ptr.offset(curr), len)
+ slice::from_raw_parts(buf_ptr.add(curr), len)
};
// stores 'e' (or 'E') and the up to 2-digit exponent
@@ -392,13 +392,13 @@ macro_rules! impl_Exp {
// SAFETY: In either case, `exp_buf` is written within bounds and `exp_ptr[..len]`
// is contained within `exp_buf` since `len <= 3`.
let exp_slice = unsafe {
- *exp_ptr.offset(0) = if upper { b'E' } else { b'e' };
+ *exp_ptr.add(0) = if upper { b'E' } else { b'e' };
let len = if exponent < 10 {
- *exp_ptr.offset(1) = (exponent as u8) + b'0';
+ *exp_ptr.add(1) = (exponent as u8) + b'0';
2
} else {
let off = exponent << 1;
- ptr::copy_nonoverlapping(lut_ptr.offset(off), exp_ptr.offset(1), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(off), exp_ptr.add(1), 2);
3
};
slice::from_raw_parts(exp_ptr, len)
@@ -479,7 +479,7 @@ mod imp {
impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
-fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut isize) {
+fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut usize) {
let buf_ptr = MaybeUninit::slice_as_mut_ptr(buf);
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
assert!(*curr > 19);
@@ -505,14 +505,14 @@ fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], cu
*curr -= 16;
- ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr + 0), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d2 as isize), buf_ptr.offset(*curr + 2), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d3 as isize), buf_ptr.offset(*curr + 4), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d4 as isize), buf_ptr.offset(*curr + 6), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d5 as isize), buf_ptr.offset(*curr + 8), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d6 as isize), buf_ptr.offset(*curr + 10), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d7 as isize), buf_ptr.offset(*curr + 12), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d8 as isize), buf_ptr.offset(*curr + 14), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d3 as usize), buf_ptr.add(*curr + 4), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d4 as usize), buf_ptr.add(*curr + 6), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d5 as usize), buf_ptr.add(*curr + 8), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d6 as usize), buf_ptr.add(*curr + 10), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d7 as usize), buf_ptr.add(*curr + 12), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d8 as usize), buf_ptr.add(*curr + 14), 2);
}
if n >= 1e8 as u64 {
let to_parse = n % 1e8 as u64;
@@ -525,10 +525,10 @@ fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], cu
let d4 = ((to_parse / 1e0 as u64) % 100) << 1;
*curr -= 8;
- ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr + 0), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d2 as isize), buf_ptr.offset(*curr + 2), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d3 as isize), buf_ptr.offset(*curr + 4), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d4 as isize), buf_ptr.offset(*curr + 6), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d3 as usize), buf_ptr.add(*curr + 4), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d4 as usize), buf_ptr.add(*curr + 6), 2);
}
// `n` < 1e8 < (1 << 32)
let mut n = n as u32;
@@ -540,8 +540,8 @@ fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], cu
let d2 = (to_parse % 100) << 1;
*curr -= 4;
- ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr + 0), 2);
- ptr::copy_nonoverlapping(lut_ptr.offset(d2 as isize), buf_ptr.offset(*curr + 2), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2);
}
// `n` < 1e4 < (1 << 16)
@@ -550,17 +550,17 @@ fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], cu
let d1 = (n % 100) << 1;
n /= 100;
*curr -= 2;
- ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr), 2);
}
// decode last 1 or 2 chars
if n < 10 {
*curr -= 1;
- *buf_ptr.offset(*curr) = (n as u8) + b'0';
+ *buf_ptr.add(*curr) = (n as u8) + b'0';
} else {
let d1 = n << 1;
*curr -= 2;
- ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr), 2);
+ ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr), 2);
}
}
}
@@ -593,21 +593,21 @@ impl fmt::Display for i128 {
fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// 2^128 is about 3*10^38, so 39 gives an extra byte of space
let mut buf = [MaybeUninit::<u8>::uninit(); 39];
- let mut curr = buf.len() as isize;
+ let mut curr = buf.len();
let (n, rem) = udiv_1e19(n);
parse_u64_into(rem, &mut buf, &mut curr);
if n != 0 {
// 0 pad up to point
- let target = (buf.len() - 19) as isize;
+ let target = buf.len() - 19;
// SAFETY: Guaranteed that we wrote at most 19 bytes, and there must be space
// remaining since it has length 39
unsafe {
ptr::write_bytes(
- MaybeUninit::slice_as_mut_ptr(&mut buf).offset(target),
+ MaybeUninit::slice_as_mut_ptr(&mut buf).add(target),
b'0',
- (curr - target) as usize,
+ curr - target,
);
}
curr = target;
@@ -616,16 +616,16 @@ fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::R
parse_u64_into(rem, &mut buf, &mut curr);
// Should this following branch be annotated with unlikely?
if n != 0 {
- let target = (buf.len() - 38) as isize;
+ let target = buf.len() - 38;
// The raw `buf_ptr` pointer is only valid until `buf` is used the next time,
// buf `buf` is not used in this scope so we are good.
let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
// SAFETY: At this point we wrote at most 38 bytes, pad up to that point,
// There can only be at most 1 digit remaining.
unsafe {
- ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize);
+ ptr::write_bytes(buf_ptr.add(target), b'0', curr - target);
curr = target - 1;
- *buf_ptr.offset(curr) = (n as u8) + b'0';
+ *buf_ptr.add(curr) = (n as u8) + b'0';
}
}
}
@@ -634,8 +634,8 @@ fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::R
// UTF-8 since `DEC_DIGITS_LUT` is
let buf_slice = unsafe {
str::from_utf8_unchecked(slice::from_raw_parts(
- MaybeUninit::slice_as_mut_ptr(&mut buf).offset(curr),
- buf.len() - curr as usize,
+ MaybeUninit::slice_as_mut_ptr(&mut buf).add(curr),
+ buf.len() - curr,
))
};
f.pad_integral(is_nonnegative, "", buf_slice)
diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs
index db2a52332..90cb79739 100644
--- a/library/core/src/future/poll_fn.rs
+++ b/library/core/src/future/poll_fn.rs
@@ -5,7 +5,9 @@ use crate::task::{Context, Poll};
/// Creates a future that wraps a function returning [`Poll`].
///
-/// Polling the future delegates to the wrapped function.
+/// Polling the future delegates to the wrapped function. If the returned future is pinned, then the
+/// captured environment of the wrapped function is also pinned in-place, so as long as the closure
+/// does not move out of its captures it can soundly create pinned references to them.
///
/// # Examples
///
@@ -41,7 +43,7 @@ pub struct PollFn<F> {
}
#[stable(feature = "future_poll_fn", since = "1.64.0")]
-impl<F> Unpin for PollFn<F> {}
+impl<F: Unpin> Unpin for PollFn<F> {}
#[stable(feature = "future_poll_fn", since = "1.64.0")]
impl<F> fmt::Debug for PollFn<F> {
@@ -57,7 +59,8 @@ where
{
type Output = T;
- fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
- (&mut self.f)(cx)
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
+ // SAFETY: We are not moving out of the pinned field.
+ (unsafe { &mut self.get_unchecked_mut().f })(cx)
}
}
diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs
index 48f20f90a..a07b63fb6 100644
--- a/library/core/src/future/ready.rs
+++ b/library/core/src/future/ready.rs
@@ -24,6 +24,30 @@ impl<T> Future for Ready<T> {
}
}
+impl<T> Ready<T> {
+ /// Consumes the `Ready`, returning the wrapped value.
+ ///
+ /// # Panics
+ ///
+ /// Will panic if this [`Ready`] was already polled to completion.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ready_into_inner)]
+ /// use std::future;
+ ///
+ /// let a = future::ready(1);
+ /// assert_eq!(a.into_inner(), 1);
+ /// ```
+ #[unstable(feature = "ready_into_inner", issue = "101196")]
+ #[must_use]
+ #[inline]
+ pub fn into_inner(self) -> T {
+ self.0.expect("Called `into_inner()` on `Ready` after completion")
+ }
+}
+
/// Creates a future that is immediately ready with a value.
///
/// Futures created through this function are functionally similar to those
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 5974562ac..aa13435e6 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -900,7 +900,7 @@ mod impls {
macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
- #[cfg_attr(not(bootstrap), doc(fake_variadic))]
+ #[doc(fake_variadic)]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 81b6d5737..c53175ba4 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -31,7 +31,7 @@ use crate::intrinsics;
///
/// `unreachable_unchecked()` can be used in situations where the compiler
/// can't prove invariants that were previously established. Such situations
-/// have a higher chance of occuring if those invariants are upheld by
+/// have a higher chance of occurring if those invariants are upheld by
/// external code that the compiler can't analyze.
/// ```
/// fn prepare_inputs(divisors: &mut Vec<u32>) {
@@ -100,7 +100,10 @@ use crate::intrinsics;
pub const unsafe fn unreachable_unchecked() -> ! {
// SAFETY: the safety contract for `intrinsics::unreachable` must
// be upheld by the caller.
- unsafe { intrinsics::unreachable() }
+ unsafe {
+ intrinsics::assert_unsafe_precondition!("hint::unreachable_unchecked must never be reached", () => false);
+ intrinsics::unreachable()
+ }
}
/// Emits a machine instruction to signal the processor that it is running in
@@ -160,19 +163,16 @@ pub const unsafe fn unreachable_unchecked() -> ! {
#[inline]
#[stable(feature = "renamed_spin_loop", since = "1.49.0")]
pub fn spin_loop() {
- #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
+ #[cfg(target_arch = "x86")]
{
- #[cfg(target_arch = "x86")]
- {
- // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
- unsafe { crate::arch::x86::_mm_pause() };
- }
+ // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
+ unsafe { crate::arch::x86::_mm_pause() };
+ }
- #[cfg(target_arch = "x86_64")]
- {
- // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
- unsafe { crate::arch::x86_64::_mm_pause() };
- }
+ #[cfg(target_arch = "x86_64")]
+ {
+ // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
+ unsafe { crate::arch::x86_64::_mm_pause() };
}
// RISC-V platform spin loop hint implementation
@@ -220,7 +220,7 @@ pub fn spin_loop() {
///
/// [`std::convert::identity`]: crate::convert::identity
#[inline]
-#[unstable(feature = "bench_black_box", issue = "64102")]
+#[stable(feature = "bench_black_box", since = "1.66.0")]
#[rustc_const_unstable(feature = "const_black_box", issue = "none")]
pub const fn black_box<T>(dummy: T) -> T {
crate::intrinsics::black_box(dummy)
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index cabc5017f..1dc79afe8 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -54,7 +54,7 @@
)]
#![allow(missing_docs)]
-use crate::marker::{Destruct, DiscriminantKind};
+use crate::marker::DiscriminantKind;
use crate::mem;
// These imports are used for simplifying intra-doc links
@@ -63,7 +63,7 @@ use crate::mem;
use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering};
#[stable(feature = "drop_in_place", since = "1.8.0")]
-#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
+#[rustc_allowed_through_unstable_modules]
#[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")]
#[inline]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
@@ -71,214 +71,6 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
unsafe { crate::ptr::drop_in_place(to_drop) }
}
-// These have been renamed.
-#[cfg(bootstrap)]
-extern "rust-intrinsic" {
- pub fn atomic_cxchg<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchg_acq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchg_rel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchg_acqrel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchg_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchg_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchg_failacq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchg_acq_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchg_acqrel_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchgweak<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchgweak_acq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchgweak_rel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchgweak_acqrel<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchgweak_relaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchgweak_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchgweak_failacq<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchgweak_acq_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_cxchgweak_acqrel_failrelaxed<T: Copy>(dst: *mut T, old: T, src: T) -> (T, bool);
- pub fn atomic_load<T: Copy>(src: *const T) -> T;
- pub fn atomic_load_acq<T: Copy>(src: *const T) -> T;
- pub fn atomic_load_relaxed<T: Copy>(src: *const T) -> T;
- pub fn atomic_load_unordered<T: Copy>(src: *const T) -> T;
- pub fn atomic_store<T: Copy>(dst: *mut T, val: T);
- pub fn atomic_store_rel<T: Copy>(dst: *mut T, val: T);
- pub fn atomic_store_relaxed<T: Copy>(dst: *mut T, val: T);
- pub fn atomic_store_unordered<T: Copy>(dst: *mut T, val: T);
- pub fn atomic_xchg<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xchg_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xchg_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xchg_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xchg_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xadd<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xadd_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xadd_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xadd_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xadd_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xsub<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xsub_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xsub_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xsub_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xsub_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_and<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_and_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_and_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_and_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_and_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_nand<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_nand_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_nand_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_nand_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_nand_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_or<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_or_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_or_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_or_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_or_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xor<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xor_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xor_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xor_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_xor_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_max<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_max_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_max_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_max_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_max_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_min<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_min_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_min_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_min_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_min_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umin<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umin_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umin_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umin_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umin_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umax<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umax_acq<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umax_rel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umax_acqrel<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_umax_relaxed<T: Copy>(dst: *mut T, src: T) -> T;
- pub fn atomic_fence();
- pub fn atomic_fence_acq();
- pub fn atomic_fence_rel();
- pub fn atomic_fence_acqrel();
- pub fn atomic_singlethreadfence();
- pub fn atomic_singlethreadfence_acq();
- pub fn atomic_singlethreadfence_rel();
- pub fn atomic_singlethreadfence_acqrel();
-}
-
-// These have been renamed.
-#[cfg(bootstrap)]
-mod atomics {
- pub use super::atomic_cxchg as atomic_cxchg_seqcst_seqcst;
- pub use super::atomic_cxchg_acq as atomic_cxchg_acquire_acquire;
- pub use super::atomic_cxchg_acq_failrelaxed as atomic_cxchg_acquire_relaxed;
- pub use super::atomic_cxchg_acqrel as atomic_cxchg_acqrel_acquire;
- pub use super::atomic_cxchg_acqrel_failrelaxed as atomic_cxchg_acqrel_relaxed;
- pub use super::atomic_cxchg_failacq as atomic_cxchg_seqcst_acquire;
- pub use super::atomic_cxchg_failrelaxed as atomic_cxchg_seqcst_relaxed;
- pub use super::atomic_cxchg_rel as atomic_cxchg_release_relaxed;
- pub use super::atomic_cxchg_relaxed as atomic_cxchg_relaxed_relaxed;
-
- pub use super::atomic_cxchgweak as atomic_cxchgweak_seqcst_seqcst;
- pub use super::atomic_cxchgweak_acq as atomic_cxchgweak_acquire_acquire;
- pub use super::atomic_cxchgweak_acq_failrelaxed as atomic_cxchgweak_acquire_relaxed;
- pub use super::atomic_cxchgweak_acqrel as atomic_cxchgweak_acqrel_acquire;
- pub use super::atomic_cxchgweak_acqrel_failrelaxed as atomic_cxchgweak_acqrel_relaxed;
- pub use super::atomic_cxchgweak_failacq as atomic_cxchgweak_seqcst_acquire;
- pub use super::atomic_cxchgweak_failrelaxed as atomic_cxchgweak_seqcst_relaxed;
- pub use super::atomic_cxchgweak_rel as atomic_cxchgweak_release_relaxed;
- pub use super::atomic_cxchgweak_relaxed as atomic_cxchgweak_relaxed_relaxed;
-
- pub use super::atomic_load as atomic_load_seqcst;
- pub use super::atomic_load_acq as atomic_load_acquire;
- pub use super::atomic_load_relaxed;
- pub use super::atomic_load_unordered;
-
- pub use super::atomic_store as atomic_store_seqcst;
- pub use super::atomic_store_rel as atomic_store_release;
- pub use super::atomic_store_relaxed;
- pub use super::atomic_store_unordered;
-
- pub use super::atomic_xchg as atomic_xchg_seqcst;
- pub use super::atomic_xchg_acq as atomic_xchg_acquire;
- pub use super::atomic_xchg_acqrel;
- pub use super::atomic_xchg_rel as atomic_xchg_release;
- pub use super::atomic_xchg_relaxed;
-
- pub use super::atomic_xadd as atomic_xadd_seqcst;
- pub use super::atomic_xadd_acq as atomic_xadd_acquire;
- pub use super::atomic_xadd_acqrel;
- pub use super::atomic_xadd_rel as atomic_xadd_release;
- pub use super::atomic_xadd_relaxed;
-
- pub use super::atomic_xsub as atomic_xsub_seqcst;
- pub use super::atomic_xsub_acq as atomic_xsub_acquire;
- pub use super::atomic_xsub_acqrel;
- pub use super::atomic_xsub_rel as atomic_xsub_release;
- pub use super::atomic_xsub_relaxed;
-
- pub use super::atomic_and as atomic_and_seqcst;
- pub use super::atomic_and_acq as atomic_and_acquire;
- pub use super::atomic_and_acqrel;
- pub use super::atomic_and_rel as atomic_and_release;
- pub use super::atomic_and_relaxed;
-
- pub use super::atomic_nand as atomic_nand_seqcst;
- pub use super::atomic_nand_acq as atomic_nand_acquire;
- pub use super::atomic_nand_acqrel;
- pub use super::atomic_nand_rel as atomic_nand_release;
- pub use super::atomic_nand_relaxed;
-
- pub use super::atomic_or as atomic_or_seqcst;
- pub use super::atomic_or_acq as atomic_or_acquire;
- pub use super::atomic_or_acqrel;
- pub use super::atomic_or_rel as atomic_or_release;
- pub use super::atomic_or_relaxed;
-
- pub use super::atomic_xor as atomic_xor_seqcst;
- pub use super::atomic_xor_acq as atomic_xor_acquire;
- pub use super::atomic_xor_acqrel;
- pub use super::atomic_xor_rel as atomic_xor_release;
- pub use super::atomic_xor_relaxed;
-
- pub use super::atomic_max as atomic_max_seqcst;
- pub use super::atomic_max_acq as atomic_max_acquire;
- pub use super::atomic_max_acqrel;
- pub use super::atomic_max_rel as atomic_max_release;
- pub use super::atomic_max_relaxed;
-
- pub use super::atomic_min as atomic_min_seqcst;
- pub use super::atomic_min_acq as atomic_min_acquire;
- pub use super::atomic_min_acqrel;
- pub use super::atomic_min_rel as atomic_min_release;
- pub use super::atomic_min_relaxed;
-
- pub use super::atomic_umin as atomic_umin_seqcst;
- pub use super::atomic_umin_acq as atomic_umin_acquire;
- pub use super::atomic_umin_acqrel;
- pub use super::atomic_umin_rel as atomic_umin_release;
- pub use super::atomic_umin_relaxed;
-
- pub use super::atomic_umax as atomic_umax_seqcst;
- pub use super::atomic_umax_acq as atomic_umax_acquire;
- pub use super::atomic_umax_acqrel;
- pub use super::atomic_umax_rel as atomic_umax_release;
- pub use super::atomic_umax_relaxed;
-
- pub use super::atomic_fence as atomic_fence_seqcst;
- pub use super::atomic_fence_acq as atomic_fence_acquire;
- pub use super::atomic_fence_acqrel;
- pub use super::atomic_fence_rel as atomic_fence_release;
-
- pub use super::atomic_singlethreadfence as atomic_singlethreadfence_seqcst;
- pub use super::atomic_singlethreadfence_acq as atomic_singlethreadfence_acquire;
- pub use super::atomic_singlethreadfence_acqrel;
- pub use super::atomic_singlethreadfence_rel as atomic_singlethreadfence_release;
-}
-
-#[cfg(bootstrap)]
-pub use atomics::*;
-
-#[cfg(not(bootstrap))]
extern "rust-intrinsic" {
// N.B., these intrinsics take raw pointers because they mutate aliased
// memory, which is not valid for either `&` or `&mut`.
@@ -945,30 +737,7 @@ extern "rust-intrinsic" {
/// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`]
/// as the `order`.
pub fn atomic_singlethreadfence_acqrel();
-}
-
-// These have been renamed.
-//
-// These are the aliases for the old names.
-// To be removed when stdarch and panic_unwind have been updated.
-#[cfg(not(bootstrap))]
-mod atomics {
- pub use super::atomic_cxchg_acqrel_acquire as atomic_cxchg_acqrel;
- pub use super::atomic_cxchg_acqrel_relaxed as atomic_cxchg_acqrel_failrelaxed;
- pub use super::atomic_cxchg_acquire_acquire as atomic_cxchg_acq;
- pub use super::atomic_cxchg_acquire_relaxed as atomic_cxchg_acq_failrelaxed;
- pub use super::atomic_cxchg_relaxed_relaxed as atomic_cxchg_relaxed;
- pub use super::atomic_cxchg_release_relaxed as atomic_cxchg_rel;
- pub use super::atomic_cxchg_seqcst_acquire as atomic_cxchg_failacq;
- pub use super::atomic_cxchg_seqcst_relaxed as atomic_cxchg_failrelaxed;
- pub use super::atomic_cxchg_seqcst_seqcst as atomic_cxchg;
- pub use super::atomic_store_seqcst as atomic_store;
-}
-
-#[cfg(not(bootstrap))]
-pub use atomics::*;
-extern "rust-intrinsic" {
/// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
/// if supported; otherwise, it is a no-op.
/// Prefetches have no effect on the behavior of the program but can change its performance
@@ -1019,6 +788,7 @@ extern "rust-intrinsic" {
/// uninitialized at that point in the control flow.
///
/// This intrinsic should not be used outside of the compiler.
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn rustc_peek<T>(_: T) -> T;
/// Aborts the execution of the process.
@@ -1036,6 +806,7 @@ extern "rust-intrinsic" {
/// On Unix, the
/// process will probably terminate with a signal like `SIGABRT`, `SIGILL`, `SIGTRAP`, `SIGSEGV` or
/// `SIGBUS`. The precise behaviour is not guaranteed and not stable.
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn abort() -> !;
/// Informs the optimizer that this point in the code is not reachable,
@@ -1074,6 +845,7 @@ extern "rust-intrinsic" {
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn likely(b: bool) -> bool;
/// Hints to the compiler that branch condition is likely to be false.
@@ -1088,6 +860,7 @@ extern "rust-intrinsic" {
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn unlikely(b: bool) -> bool;
/// Executes a breakpoint trap, for inspection by a debugger.
@@ -1107,6 +880,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is [`core::mem::size_of`].
#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn size_of<T>() -> usize;
/// The minimum alignment of a type.
@@ -1118,6 +892,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is [`core::mem::align_of`].
#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn min_align_of<T>() -> usize;
/// The preferred alignment of a type.
///
@@ -1146,6 +921,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is [`core::any::type_name`].
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn type_name<T: ?Sized>() -> &'static str;
/// Gets an identifier which is globally unique to the specified type. This
@@ -1159,6 +935,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn type_id<T: ?Sized + 'static>() -> u64;
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
@@ -1166,6 +943,7 @@ extern "rust-intrinsic" {
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn assert_inhabited<T>();
/// A guard for unsafe functions that cannot ever be executed if `T` does not permit
@@ -1173,6 +951,7 @@ extern "rust-intrinsic" {
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn assert_zero_valid<T>();
/// A guard for unsafe functions that cannot ever be executed if `T` has invalid
@@ -1180,6 +959,7 @@ extern "rust-intrinsic" {
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn assert_uninit_valid<T>();
/// Gets a reference to a static `Location` indicating where it was called.
@@ -1191,6 +971,7 @@ extern "rust-intrinsic" {
///
/// Consider using [`core::panic::Location::caller`] instead.
#[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn caller_location() -> &'static crate::panic::Location<'static>;
/// Moves a value out of scope without running drop glue.
@@ -1203,6 +984,7 @@ extern "rust-intrinsic" {
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
#[rustc_const_unstable(feature = "const_intrinsic_forget", issue = "none")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn forget<T: ?Sized>(_: T);
/// Reinterprets the bits of a value of one type as another type.
@@ -1212,14 +994,14 @@ extern "rust-intrinsic" {
/// `transmute` is semantically equivalent to a bitwise move of one type
/// into another. It copies the bits from the source value into the
/// destination value, then forgets the original. Note that source and destination
- /// are passed by-value, which means if `T` or `U` contain padding, that padding
+ /// are passed by-value, which means if `Src` or `Dst` contain padding, that padding
/// is *not* guaranteed to be preserved by `transmute`.
///
/// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at
/// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler
/// will generate code *assuming that you, the programmer, ensure that there will never be
/// undefined behavior*. It is therefore your responsibility to guarantee that every value
- /// passed to `transmute` is valid at both types `T` and `U`. Failing to uphold this condition
+ /// passed to `transmute` is valid at both types `Src` and `Dst`. Failing to uphold this condition
/// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly
/// unsafe**. `transmute` should be the absolute last resort.
///
@@ -1230,7 +1012,7 @@ extern "rust-intrinsic" {
///
/// Because `transmute` is a by-value operation, alignment of the *transmuted values
/// themselves* is not a concern. As with any other function, the compiler already ensures
- /// both `T` and `U` are properly aligned. However, when transmuting values that *point
+ /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point
/// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper
/// alignment of the pointed-to values.
///
@@ -1313,7 +1095,7 @@ extern "rust-intrinsic" {
/// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined
/// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave
/// as expected -- this is touching on many unspecified aspects of the Rust memory model.
- /// Depending on what the code is doing, the following alternatives are preferrable to
+ /// Depending on what the code is doing, the following alternatives are preferable to
/// pointer-to-integer transmutation:
/// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a
/// type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit].
@@ -1463,10 +1245,10 @@ extern "rust-intrinsic" {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
+ #[rustc_allowed_through_unstable_modules]
#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
#[rustc_diagnostic_item = "transmute"]
- pub fn transmute<T, U>(e: T) -> U;
+ pub fn transmute<Src, Dst>(src: Src) -> Dst;
/// Returns `true` if the actual type given as `T` requires drop
/// glue; returns `false` if the actual type provided for `T`
@@ -1482,6 +1264,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
#[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn needs_drop<T: ?Sized>() -> bool;
/// Calculates the offset from a pointer.
@@ -1518,6 +1301,17 @@ extern "rust-intrinsic" {
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
+ /// Masks out bits of the pointer according to a mask.
+ ///
+ /// Note that, unlike most intrinsics, this is safe to call;
+ /// it does not require an `unsafe` block.
+ /// Therefore, implementations must not require the user to uphold
+ /// any safety invariants.
+ ///
+ /// Consider using [`pointer::mask`] instead.
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+ pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;
+
/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
/// a size of `count` * `size_of::<T>()` and an alignment of
/// `min_align_of::<T>()`
@@ -1707,6 +1501,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is
/// [`f32::min`]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn minnumf32(x: f32, y: f32) -> f32;
/// Returns the minimum of two `f64` values.
///
@@ -1717,6 +1512,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is
/// [`f64::min`]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn minnumf64(x: f64, y: f64) -> f64;
/// Returns the maximum of two `f32` values.
///
@@ -1727,6 +1523,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is
/// [`f32::max`]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn maxnumf32(x: f32, y: f32) -> f32;
/// Returns the maximum of two `f64` values.
///
@@ -1737,6 +1534,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is
/// [`f64::max`]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn maxnumf64(x: f64, y: f64) -> f64;
/// Copies the sign from `y` to `x` for `f32` values.
@@ -1857,6 +1655,7 @@ extern "rust-intrinsic" {
/// primitives via the `count_ones` method. For example,
/// [`u32::count_ones`]
#[rustc_const_stable(feature = "const_ctpop", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn ctpop<T: Copy>(x: T) -> T;
/// Returns the number of leading unset bits (zeroes) in an integer type `T`.
@@ -1894,6 +1693,7 @@ extern "rust-intrinsic" {
/// assert_eq!(num_leading, 16);
/// ```
#[rustc_const_stable(feature = "const_ctlz", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn ctlz<T: Copy>(x: T) -> T;
/// Like `ctlz`, but extra-unsafe as it returns `undef` when
@@ -1950,6 +1750,7 @@ extern "rust-intrinsic" {
/// assert_eq!(num_trailing, 16);
/// ```
#[rustc_const_stable(feature = "const_cttz", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn cttz<T: Copy>(x: T) -> T;
/// Like `cttz`, but extra-unsafe as it returns `undef` when
@@ -1982,6 +1783,7 @@ extern "rust-intrinsic" {
/// primitives via the `swap_bytes` method. For example,
/// [`u32::swap_bytes`]
#[rustc_const_stable(feature = "const_bswap", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn bswap<T: Copy>(x: T) -> T;
/// Reverses the bits in an integer type `T`.
@@ -1995,6 +1797,7 @@ extern "rust-intrinsic" {
/// primitives via the `reverse_bits` method. For example,
/// [`u32::reverse_bits`]
#[rustc_const_stable(feature = "const_bitreverse", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn bitreverse<T: Copy>(x: T) -> T;
/// Performs checked integer addition.
@@ -2008,6 +1811,7 @@ extern "rust-intrinsic" {
/// primitives via the `overflowing_add` method. For example,
/// [`u32::overflowing_add`]
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
/// Performs checked integer subtraction
@@ -2021,6 +1825,7 @@ extern "rust-intrinsic" {
/// primitives via the `overflowing_sub` method. For example,
/// [`u32::overflowing_sub`]
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn sub_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
/// Performs checked integer multiplication
@@ -2034,6 +1839,7 @@ extern "rust-intrinsic" {
/// primitives via the `overflowing_mul` method. For example,
/// [`u32::overflowing_mul`]
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
/// Performs an exact division, resulting in undefined behavior where
@@ -2108,6 +1914,7 @@ extern "rust-intrinsic" {
/// primitives via the `rotate_left` method. For example,
/// [`u32::rotate_left`]
#[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
/// Performs rotate right.
@@ -2121,6 +1928,7 @@ extern "rust-intrinsic" {
/// primitives via the `rotate_right` method. For example,
/// [`u32::rotate_right`]
#[rustc_const_stable(feature = "const_int_rotate", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
/// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
@@ -2134,6 +1942,7 @@ extern "rust-intrinsic" {
/// primitives via the `wrapping_add` method. For example,
/// [`u32::wrapping_add`]
#[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn wrapping_add<T: Copy>(a: T, b: T) -> T;
/// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
///
@@ -2146,6 +1955,7 @@ extern "rust-intrinsic" {
/// primitives via the `wrapping_sub` method. For example,
/// [`u32::wrapping_sub`]
#[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T;
/// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
///
@@ -2158,6 +1968,7 @@ extern "rust-intrinsic" {
/// primitives via the `wrapping_mul` method. For example,
/// [`u32::wrapping_mul`]
#[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T;
/// Computes `a + b`, saturating at numeric bounds.
@@ -2171,6 +1982,7 @@ extern "rust-intrinsic" {
/// primitives via the `saturating_add` method. For example,
/// [`u32::saturating_add`]
#[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn saturating_add<T: Copy>(a: T, b: T) -> T;
/// Computes `a - b`, saturating at numeric bounds.
///
@@ -2183,6 +1995,7 @@ extern "rust-intrinsic" {
/// primitives via the `saturating_sub` method. For example,
/// [`u32::saturating_sub`]
#[rustc_const_stable(feature = "const_int_saturating", since = "1.40.0")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn saturating_sub<T: Copy>(a: T, b: T) -> T;
/// Returns the value of the discriminant for the variant in 'v';
@@ -2195,6 +2008,7 @@ extern "rust-intrinsic" {
///
/// The stabilized version of this intrinsic is [`core::mem::discriminant`].
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
/// Returns the number of variants of the type `T` cast to a `usize`;
@@ -2207,6 +2021,7 @@ extern "rust-intrinsic" {
///
/// The to-be-stabilized version of this intrinsic is [`mem::variant_count`].
#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn variant_count<T>() -> usize;
/// Rust's "try catch" construct which invokes the function pointer `try_fn`
@@ -2223,30 +2038,25 @@ extern "rust-intrinsic" {
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
/// See documentation of `<*const T>::offset_from` for details.
- #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
+ #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
/// See documentation of `<*const T>::sub_ptr` for details.
- #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
+ #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
pub fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize;
/// See documentation of `<*const T>::guaranteed_eq` for details.
+ /// Returns `2` if the result is unknown.
+ /// Returns `1` if the pointers are guaranteed equal
+ /// Returns `0` if the pointers are guaranteed inequal
///
/// Note that, unlike most intrinsics, this is safe to call;
/// it does not require an `unsafe` block.
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
- pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
-
- /// See documentation of `<*const T>::guaranteed_ne` for details.
- ///
- /// Note that, unlike most intrinsics, this is safe to call;
- /// it does not require an `unsafe` block.
- /// Therefore, implementations must not require the user to uphold
- /// any safety invariants.
- #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
- pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
+ pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
/// Allocates a block of memory at compile time.
/// At runtime, just returns a null pointer.
@@ -2282,7 +2092,8 @@ extern "rust-intrinsic" {
///
/// # Safety
///
- /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized.
+ /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized or carry a
+ /// pointer value.
/// Note that this is a stricter criterion than just the *values* being
/// fully-initialized: if `T` has padding, it's UB to call this intrinsic.
///
@@ -2295,17 +2106,74 @@ extern "rust-intrinsic" {
///
/// [`std::hint::black_box`]: crate::hint::black_box
#[rustc_const_unstable(feature = "const_black_box", issue = "none")]
+ #[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
pub fn black_box<T>(dummy: T) -> T;
/// `ptr` must point to a vtable.
/// The intrinsic will return the size stored in that vtable.
- #[cfg(not(bootstrap))]
pub fn vtable_size(ptr: *const ()) -> usize;
/// `ptr` must point to a vtable.
/// The intrinsic will return the alignment stored in that vtable.
- #[cfg(not(bootstrap))]
pub fn vtable_align(ptr: *const ()) -> usize;
+
+ /// Selects which function to call depending on the context.
+ ///
+ /// If this function is evaluated at compile-time, then a call to this
+ /// intrinsic will be replaced with a call to `called_in_const`. It gets
+ /// replaced with a call to `called_at_rt` otherwise.
+ ///
+ /// # Type Requirements
+ ///
+ /// The two functions must be both function items. They cannot be function
+ /// pointers or closures. The first function must be a `const fn`.
+ ///
+ /// `arg` will be the tupled arguments that will be passed to either one of
+ /// the two functions, therefore, both functions must accept the same type of
+ /// arguments. Both functions must return RET.
+ ///
+ /// # Safety
+ ///
+ /// The two functions must behave observably equivalent. Safe code in other
+ /// crates may assume that calling a `const fn` at compile-time and at run-time
+ /// produces the same result. A function that produces a different result when
+ /// evaluated at run-time, or has any other observable side-effects, is
+ /// *unsound*.
+ ///
+ /// Here is an example of how this could cause a problem:
+ /// ```no_run
+ /// #![feature(const_eval_select)]
+ /// #![feature(core_intrinsics)]
+ /// use std::hint::unreachable_unchecked;
+ /// use std::intrinsics::const_eval_select;
+ ///
+ /// // Crate A
+ /// pub const fn inconsistent() -> i32 {
+ /// fn runtime() -> i32 { 1 }
+ /// const fn compiletime() -> i32 { 2 }
+ ///
+ /// unsafe {
+ // // ⚠ This code violates the required equivalence of `compiletime`
+ /// // and `runtime`.
+ /// const_eval_select((), compiletime, runtime)
+ /// }
+ /// }
+ ///
+ /// // Crate B
+ /// const X: i32 = inconsistent();
+ /// let x = inconsistent();
+ /// if x != X { unsafe { unreachable_unchecked(); }}
+ /// ```
+ ///
+ /// This code causes Undefined Behavior when being run, since the
+ /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
+ /// which violates the principle that a `const fn` must behave the same at
+ /// compile-time and at run-time. The unsafe code in crate B is fine.
+ #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
+ pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
+ where
+ G: FnOnce<ARG, Output = RET>,
+ F: FnOnce<ARG, Output = RET>;
}
// Some functions are defined here because they accidentally got made
@@ -2316,6 +2184,11 @@ extern "rust-intrinsic" {
/// Check that the preconditions of an unsafe function are followed, if debug_assertions are on,
/// and only at runtime.
///
+/// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)`
+/// where the names specified will be moved into the macro as captured variables, and defines an item
+/// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics
+/// for the function declaractions and can be omitted if there is no generics.
+///
/// # Safety
///
/// Invoking this macro is only sound if the following code is already UB when the passed
@@ -2330,18 +2203,23 @@ extern "rust-intrinsic" {
/// the occasional mistake, and this check should help them figure things out.
#[allow_internal_unstable(const_eval_select)] // permit this to be called in stably-const fn
macro_rules! assert_unsafe_precondition {
- ($e:expr) => {
+ ($name:expr, $([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr) => {
if cfg!(debug_assertions) {
- // Use a closure so that we can capture arbitrary expressions from the invocation
- let runtime = || {
+ // allow non_snake_case to allow capturing const generics
+ #[allow(non_snake_case)]
+ #[inline(always)]
+ fn runtime$(<$($tt)*>)?($($i:$ty),*) {
if !$e {
- // abort instead of panicking to reduce impact on code size
- ::core::intrinsics::abort();
+ // don't unwind to reduce impact on code size
+ ::core::panicking::panic_str_nounwind(
+ concat!("unsafe precondition(s) violated: ", $name)
+ );
}
- };
- const fn comptime() {}
+ }
+ #[allow(non_snake_case)]
+ const fn comptime$(<$($tt)*>)?($(_:$ty),*) {}
- ::core::intrinsics::const_eval_select((), comptime, runtime);
+ ::core::intrinsics::const_eval_select(($($i,)*), comptime, runtime);
}
};
}
@@ -2350,7 +2228,17 @@ pub(crate) use assert_unsafe_precondition;
/// Checks whether `ptr` is properly aligned with respect to
/// `align_of::<T>()`.
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
- !ptr.is_null() && ptr.addr() % mem::align_of::<T>() == 0
+ !ptr.is_null() && ptr.is_aligned()
+}
+
+/// Checks whether an allocation of `len` instances of `T` exceeds
+/// the maximum allowed allocation size.
+pub(crate) fn is_valid_allocation_size<T>(len: usize) -> bool {
+ let max_len = const {
+ let size = crate::mem::size_of::<T>();
+ if size == 0 { usize::MAX } else { isize::MAX as usize / size }
+ };
+ len <= max_len
}
/// Checks whether the regions of memory starting at `src` and `dst` of size
@@ -2420,9 +2308,9 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
/// dst.reserve(src_len);
///
/// unsafe {
-/// // The call to offset is always safe because `Vec` will never
+/// // The call to add is always safe because `Vec` will never
/// // allocate more than `isize::MAX` bytes.
-/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize);
+/// let dst_ptr = dst.as_mut_ptr().add(dst_len);
/// let src_ptr = src.as_ptr();
///
/// // Truncate `src` without dropping its contents. We do this first,
@@ -2451,7 +2339,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
#[doc(alias = "memcpy")]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
+#[rustc_allowed_through_unstable_modules]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -2465,6 +2353,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
// upheld by the caller.
unsafe {
assert_unsafe_precondition!(
+ "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
+ and the specified memory ranges do not overlap",
+ [T](src: *const T, dst: *mut T, count: usize) =>
is_aligned_and_not_null(src)
&& is_aligned_and_not_null(dst)
&& is_nonoverlapping(src, dst, count)
@@ -2538,7 +2429,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
/// ```
#[doc(alias = "memmove")]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
+#[rustc_allowed_through_unstable_modules]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -2550,7 +2441,11 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
// SAFETY: the safety contract for `copy` must be upheld by the caller.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!(
+ "ptr::copy requires that both pointer arguments are aligned aligned and non-null",
+ [T](src: *const T, dst: *mut T) =>
+ is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)
+ );
copy(src, dst, count)
}
}
@@ -2606,7 +2501,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
/// ```
#[doc(alias = "memset")]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
+#[rustc_allowed_through_unstable_modules]
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
@@ -2618,99 +2513,10 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!(
+ "ptr::write_bytes requires that the destination pointer is aligned and non-null",
+ [T](dst: *mut T) => is_aligned_and_not_null(dst)
+ );
write_bytes(dst, val, count)
}
}
-
-/// Selects which function to call depending on the context.
-///
-/// If this function is evaluated at compile-time, then a call to this
-/// intrinsic will be replaced with a call to `called_in_const`. It gets
-/// replaced with a call to `called_at_rt` otherwise.
-///
-/// # Type Requirements
-///
-/// The two functions must be both function items. They cannot be function
-/// pointers or closures.
-///
-/// `arg` will be the arguments that will be passed to either one of the
-/// two functions, therefore, both functions must accept the same type of
-/// arguments. Both functions must return RET.
-///
-/// # Safety
-///
-/// The two functions must behave observably equivalent. Safe code in other
-/// crates may assume that calling a `const fn` at compile-time and at run-time
-/// produces the same result. A function that produces a different result when
-/// evaluated at run-time, or has any other observable side-effects, is
-/// *unsound*.
-///
-/// Here is an example of how this could cause a problem:
-/// ```no_run
-/// #![feature(const_eval_select)]
-/// #![feature(core_intrinsics)]
-/// use std::hint::unreachable_unchecked;
-/// use std::intrinsics::const_eval_select;
-///
-/// // Crate A
-/// pub const fn inconsistent() -> i32 {
-/// fn runtime() -> i32 { 1 }
-/// const fn compiletime() -> i32 { 2 }
-///
-/// unsafe {
-// // ⚠ This code violates the required equivalence of `compiletime`
-/// // and `runtime`.
-/// const_eval_select((), compiletime, runtime)
-/// }
-/// }
-///
-/// // Crate B
-/// const X: i32 = inconsistent();
-/// let x = inconsistent();
-/// if x != X { unsafe { unreachable_unchecked(); }}
-/// ```
-///
-/// This code causes Undefined Behavior when being run, since the
-/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
-/// which violates the principle that a `const fn` must behave the same at
-/// compile-time and at run-time. The unsafe code in crate B is fine.
-#[unstable(
- feature = "const_eval_select",
- issue = "none",
- reason = "const_eval_select will never be stable"
-)]
-#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
-#[lang = "const_eval_select"]
-#[rustc_do_not_const_check]
-#[inline]
-pub const unsafe fn const_eval_select<ARG, F, G, RET>(
- arg: ARG,
- _called_in_const: F,
- called_at_rt: G,
-) -> RET
-where
- F: ~const FnOnce<ARG, Output = RET>,
- G: FnOnce<ARG, Output = RET> + ~const Destruct,
-{
- called_at_rt.call_once(arg)
-}
-
-#[unstable(
- feature = "const_eval_select",
- issue = "none",
- reason = "const_eval_select will never be stable"
-)]
-#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
-#[lang = "const_eval_select_ct"]
-pub const unsafe fn const_eval_select_ct<ARG, F, G, RET>(
- arg: ARG,
- called_in_const: F,
- _called_at_rt: G,
-) -> RET
-where
- F: ~const FnOnce<ARG, Output = RET>,
- G: FnOnce<ARG, Output = RET> + ~const Destruct,
-{
- called_in_const.call_once(arg)
-}
diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs
new file mode 100644
index 000000000..d4fb88610
--- /dev/null
+++ b/library/core/src/iter/adapters/array_chunks.rs
@@ -0,0 +1,170 @@
+use crate::array;
+use crate::iter::{ByRefSized, FusedIterator, Iterator};
+use crate::ops::{ControlFlow, Try};
+
+/// An iterator over `N` elements of the iterator at a time.
+///
+/// The chunks do not overlap. If `N` does not divide the length of the
+/// iterator, then the last up to `N-1` elements will be omitted.
+///
+/// This `struct` is created by the [`array_chunks`][Iterator::array_chunks]
+/// method on [`Iterator`]. See its documentation for more.
+#[derive(Debug, Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+pub struct ArrayChunks<I: Iterator, const N: usize> {
+ iter: I,
+ remainder: Option<array::IntoIter<I::Item, N>>,
+}
+
+impl<I, const N: usize> ArrayChunks<I, N>
+where
+ I: Iterator,
+{
+ #[track_caller]
+ pub(in crate::iter) fn new(iter: I) -> Self {
+ assert!(N != 0, "chunk size must be non-zero");
+ Self { iter, remainder: None }
+ }
+
+ /// Returns an iterator over the remaining elements of the original iterator
+ /// that are not going to be returned by this iterator. The returned
+ /// iterator will yield at most `N-1` elements.
+ #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+ #[inline]
+ pub fn into_remainder(self) -> Option<array::IntoIter<I::Item, N>> {
+ self.remainder
+ }
+}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> Iterator for ArrayChunks<I, N>
+where
+ I: Iterator,
+{
+ type Item = [I::Item; N];
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ self.try_for_each(ControlFlow::Break).break_value()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (lower, upper) = self.iter.size_hint();
+
+ (lower / N, upper.map(|n| n / N))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.iter.count() / N
+ }
+
+ fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ let mut acc = init;
+ loop {
+ match self.iter.next_chunk() {
+ Ok(chunk) => acc = f(acc, chunk)?,
+ Err(remainder) => {
+ // Make sure to not override `self.remainder` with an empty array
+ // when `next` is called after `ArrayChunks` exhaustion.
+ self.remainder.get_or_insert(remainder);
+
+ break try { acc };
+ }
+ }
+ }
+ }
+
+ impl_fold_via_try_fold! { fold -> try_fold }
+}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> DoubleEndedIterator for ArrayChunks<I, N>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.try_rfold((), |(), x| ControlFlow::Break(x)).break_value()
+ }
+
+ fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ // We are iterating from the back we need to first handle the remainder.
+ self.next_back_remainder();
+
+ let mut acc = init;
+ let mut iter = ByRefSized(&mut self.iter).rev();
+
+ // NB remainder is handled by `next_back_remainder`, so
+ // `next_chunk` can't return `Err` with non-empty remainder
+ // (assuming correct `I as ExactSizeIterator` impl).
+ while let Ok(mut chunk) = iter.next_chunk() {
+ // FIXME: do not do double reverse
+ // (we could instead add `next_chunk_back` for example)
+ chunk.reverse();
+ acc = f(acc, chunk)?
+ }
+
+ try { acc }
+ }
+
+ impl_fold_via_try_fold! { rfold -> try_rfold }
+}
+
+impl<I, const N: usize> ArrayChunks<I, N>
+where
+ I: DoubleEndedIterator + ExactSizeIterator,
+{
+ /// Updates `self.remainder` such that `self.iter.len` is divisible by `N`.
+ fn next_back_remainder(&mut self) {
+ // Make sure to not override `self.remainder` with an empty array
+ // when `next_back` is called after `ArrayChunks` exhaustion.
+ if self.remainder.is_some() {
+ return;
+ }
+
+ // We use the `ExactSizeIterator` implementation of the underlying
+ // iterator to know how many remaining elements there are.
+ let rem = self.iter.len() % N;
+
+ // Take the last `rem` elements out of `self.iter`.
+ let mut remainder =
+ // SAFETY: `unwrap_err` always succeeds because x % N < N for all x.
+ unsafe { self.iter.by_ref().rev().take(rem).next_chunk().unwrap_err_unchecked() };
+
+ // We used `.rev()` above, so we need to re-reverse the reminder
+ remainder.as_mut_slice().reverse();
+ self.remainder = Some(remainder);
+ }
+}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N>
+where
+ I: ExactSizeIterator,
+{
+ #[inline]
+ fn len(&self) -> usize {
+ self.iter.len() / N
+ }
+
+ #[inline]
+ fn is_empty(&self) -> bool {
+ self.iter.len() < N
+ }
+}
diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs
index cc1e8e8a2..1945e402f 100644
--- a/library/core/src/iter/adapters/by_ref_sized.rs
+++ b/library/core/src/iter/adapters/by_ref_sized.rs
@@ -1,4 +1,7 @@
-use crate::ops::Try;
+use crate::{
+ const_closure::ConstFnMutClosure,
+ ops::{NeverShortCircuit, Try},
+};
/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
///
@@ -8,36 +11,41 @@ use crate::ops::Try;
#[derive(Debug)]
pub struct ByRefSized<'a, I>(pub &'a mut I);
+// The following implementations use UFCS-style, rather than trusting autoderef,
+// to avoid accidentally calling the `&mut Iterator` implementations.
+
#[unstable(feature = "std_internals", issue = "none")]
impl<I: Iterator> Iterator for ByRefSized<'_, I> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
- self.0.next()
+ I::next(self.0)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- self.0.size_hint()
+ I::size_hint(self.0)
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
- self.0.advance_by(n)
+ I::advance_by(self.0, n)
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
- self.0.nth(n)
+ I::nth(self.0, n)
}
#[inline]
- fn fold<B, F>(self, init: B, f: F) -> B
+ fn fold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
- self.0.fold(init, f)
+ // `fold` needs ownership, so this can't forward directly.
+ I::try_fold(self.0, init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp))
+ .0
}
#[inline]
@@ -46,7 +54,7 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
- self.0.try_fold(init, f)
+ I::try_fold(self.0, init, f)
}
}
@@ -54,25 +62,31 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
- self.0.next_back()
+ I::next_back(self.0)
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
- self.0.advance_back_by(n)
+ I::advance_back_by(self.0, n)
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- self.0.nth_back(n)
+ I::nth_back(self.0, n)
}
#[inline]
- fn rfold<B, F>(self, init: B, f: F) -> B
+ fn rfold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
- self.0.rfold(init, f)
+ // `rfold` needs ownership, so this can't forward directly.
+ I::try_rfold(
+ self.0,
+ init,
+ ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp),
+ )
+ .0
}
#[inline]
@@ -81,6 +95,6 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
- self.0.try_rfold(init, f)
+ I::try_rfold(self.0, init, f)
}
}
diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs
index f9bfd77d7..62d3afb81 100644
--- a/library/core/src/iter/adapters/copied.rs
+++ b/library/core/src/iter/adapters/copied.rs
@@ -2,7 +2,10 @@ use crate::iter::adapters::{
zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::iter::{FusedIterator, TrustedLen};
+use crate::mem::MaybeUninit;
+use crate::mem::SizedTypeProperties;
use crate::ops::Try;
+use crate::{array, ptr};
/// An iterator that copies the elements of an underlying iterator.
///
@@ -44,6 +47,15 @@ where
self.it.next().copied()
}
+ fn next_chunk<const N: usize>(
+ &mut self,
+ ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
+ where
+ Self: Sized,
+ {
+ <I as SpecNextChunk<'_, N, T>>::spec_next_chunk(&mut self.it)
+ }
+
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
@@ -166,3 +178,65 @@ where
T: Copy,
{
}
+
+trait SpecNextChunk<'a, const N: usize, T: 'a>: Iterator<Item = &'a T>
+where
+ T: Copy,
+{
+ fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>>;
+}
+
+impl<'a, const N: usize, I, T: 'a> SpecNextChunk<'a, N, T> for I
+where
+ I: Iterator<Item = &'a T>,
+ T: Copy,
+{
+ default fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
+ array::iter_next_chunk(&mut self.map(|e| *e))
+ }
+}
+
+impl<'a, const N: usize, T: 'a> SpecNextChunk<'a, N, T> for crate::slice::Iter<'a, T>
+where
+ T: Copy,
+{
+ fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
+ let mut raw_array = MaybeUninit::uninit_array();
+
+ let len = self.len();
+
+ if T::IS_ZST {
+ if len < N {
+ let _ = self.advance_by(len);
+ // SAFETY: ZSTs can be conjured ex nihilo; only the amount has to be correct
+ return Err(unsafe { array::IntoIter::new_unchecked(raw_array, 0..len) });
+ }
+
+ let _ = self.advance_by(N);
+ // SAFETY: ditto
+ return Ok(unsafe { MaybeUninit::array_assume_init(raw_array) });
+ }
+
+ if len < N {
+ // SAFETY: `len` indicates that this many elements are available and we just checked that
+ // it fits into the array.
+ unsafe {
+ ptr::copy_nonoverlapping(
+ self.as_ref().as_ptr(),
+ raw_array.as_mut_ptr() as *mut T,
+ len,
+ );
+ let _ = self.advance_by(len);
+ return Err(array::IntoIter::new_unchecked(raw_array, 0..len));
+ }
+ }
+
+ // SAFETY: `len` is larger than the array size. Copy a fixed amount here to fully initialize
+ // the array.
+ unsafe {
+ ptr::copy_nonoverlapping(self.as_ref().as_ptr(), raw_array.as_mut_ptr() as *mut T, N);
+ let _ = self.advance_by(N);
+ Ok(MaybeUninit::array_assume_init(raw_array))
+ }
+ }
+}
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 15a120e35..307016c26 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -1,6 +1,6 @@
use crate::fmt;
use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen};
-use crate::ops::Try;
+use crate::ops::{ControlFlow, Try};
/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
@@ -73,6 +73,21 @@ where
{
self.inner.fold(init, fold)
}
+
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+ self.inner.advance_by(n)
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.inner.count()
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ self.inner.last()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -103,6 +118,11 @@ where
{
self.inner.rfold(init, fold)
}
+
+ #[inline]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+ self.inner.advance_back_by(n)
+ }
}
#[stable(feature = "fused", since = "1.26.0")]
@@ -214,6 +234,21 @@ where
{
self.inner.fold(init, fold)
}
+
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+ self.inner.advance_by(n)
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.inner.count()
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ self.inner.last()
+ }
}
#[stable(feature = "iterator_flatten", since = "1.29.0")]
@@ -244,6 +279,11 @@ where
{
self.inner.rfold(init, fold)
}
+
+ #[inline]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+ self.inner.advance_back_by(n)
+ }
}
#[stable(feature = "iterator_flatten", since = "1.29.0")]
@@ -280,6 +320,144 @@ where
}
}
+impl<I, U> FlattenCompat<I, U>
+where
+ I: Iterator<Item: IntoIterator<IntoIter = U>>,
+{
+ /// Folds the inner iterators into an accumulator by applying an operation.
+ ///
+ /// Folds over the inner iterators, not over their elements. Is used by the `fold`, `count`,
+ /// and `last` methods.
+ #[inline]
+ fn iter_fold<Acc, Fold>(self, mut acc: Acc, mut fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, U) -> Acc,
+ {
+ #[inline]
+ fn flatten<T: IntoIterator, Acc>(
+ fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc,
+ ) -> impl FnMut(Acc, T) -> Acc + '_ {
+ move |acc, iter| fold(acc, iter.into_iter())
+ }
+
+ if let Some(iter) = self.frontiter {
+ acc = fold(acc, iter);
+ }
+
+ acc = self.iter.fold(acc, flatten(&mut fold));
+
+ if let Some(iter) = self.backiter {
+ acc = fold(acc, iter);
+ }
+
+ acc
+ }
+
+ /// Folds over the inner iterators as long as the given function returns successfully,
+ /// always storing the most recent inner iterator in `self.frontiter`.
+ ///
+ /// Folds over the inner iterators, not over their elements. Is used by the `try_fold` and
+ /// `advance_by` methods.
+ #[inline]
+ fn iter_try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, mut fold: Fold) -> R
+ where
+ Fold: FnMut(Acc, &mut U) -> R,
+ R: Try<Output = Acc>,
+ {
+ #[inline]
+ fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>(
+ frontiter: &'a mut Option<T::IntoIter>,
+ fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R,
+ ) -> impl FnMut(Acc, T) -> R + 'a {
+ move |acc, iter| fold(acc, frontiter.insert(iter.into_iter()))
+ }
+
+ if let Some(iter) = &mut self.frontiter {
+ acc = fold(acc, iter)?;
+ }
+ self.frontiter = None;
+
+ acc = self.iter.try_fold(acc, flatten(&mut self.frontiter, &mut fold))?;
+ self.frontiter = None;
+
+ if let Some(iter) = &mut self.backiter {
+ acc = fold(acc, iter)?;
+ }
+ self.backiter = None;
+
+ try { acc }
+ }
+}
+
+impl<I, U> FlattenCompat<I, U>
+where
+ I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U>>,
+{
+ /// Folds the inner iterators into an accumulator by applying an operation, starting form the
+ /// back.
+ ///
+ /// Folds over the inner iterators, not over their elements. Is used by the `rfold` method.
+ #[inline]
+ fn iter_rfold<Acc, Fold>(self, mut acc: Acc, mut fold: Fold) -> Acc
+ where
+ Fold: FnMut(Acc, U) -> Acc,
+ {
+ #[inline]
+ fn flatten<T: IntoIterator, Acc>(
+ fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc,
+ ) -> impl FnMut(Acc, T) -> Acc + '_ {
+ move |acc, iter| fold(acc, iter.into_iter())
+ }
+
+ if let Some(iter) = self.backiter {
+ acc = fold(acc, iter);
+ }
+
+ acc = self.iter.rfold(acc, flatten(&mut fold));
+
+ if let Some(iter) = self.frontiter {
+ acc = fold(acc, iter);
+ }
+
+ acc
+ }
+
+ /// Folds over the inner iterators in reverse order as long as the given function returns
+ /// successfully, always storing the most recent inner iterator in `self.backiter`.
+ ///
+ /// Folds over the inner iterators, not over their elements. Is used by the `try_rfold` and
+ /// `advance_back_by` methods.
+ #[inline]
+ fn iter_try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, mut fold: Fold) -> R
+ where
+ Fold: FnMut(Acc, &mut U) -> R,
+ R: Try<Output = Acc>,
+ {
+ #[inline]
+ fn flatten<'a, T: IntoIterator, Acc, R: Try>(
+ backiter: &'a mut Option<T::IntoIter>,
+ fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R,
+ ) -> impl FnMut(Acc, T) -> R + 'a {
+ move |acc, iter| fold(acc, backiter.insert(iter.into_iter()))
+ }
+
+ if let Some(iter) = &mut self.backiter {
+ acc = fold(acc, iter)?;
+ }
+ self.backiter = None;
+
+ acc = self.iter.try_rfold(acc, flatten(&mut self.backiter, &mut fold))?;
+ self.backiter = None;
+
+ if let Some(iter) = &mut self.frontiter {
+ acc = fold(acc, iter)?;
+ }
+ self.frontiter = None;
+
+ try { acc }
+ }
+}
+
impl<I, U> Iterator for FlattenCompat<I, U>
where
I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -323,99 +501,74 @@ where
}
#[inline]
- fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
+ fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Output = Acc>,
{
#[inline]
- fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>(
- frontiter: &'a mut Option<T::IntoIter>,
- fold: &'a mut impl FnMut(Acc, T::Item) -> R,
- ) -> impl FnMut(Acc, T) -> R + 'a {
- move |acc, x| {
- let mut mid = x.into_iter();
- let r = mid.try_fold(acc, &mut *fold);
- *frontiter = Some(mid);
- r
- }
- }
-
- if let Some(ref mut front) = self.frontiter {
- init = front.try_fold(init, &mut fold)?;
+ fn flatten<U: Iterator, Acc, R: Try<Output = Acc>>(
+ mut fold: impl FnMut(Acc, U::Item) -> R,
+ ) -> impl FnMut(Acc, &mut U) -> R {
+ move |acc, iter| iter.try_fold(acc, &mut fold)
}
- self.frontiter = None;
- init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
- self.frontiter = None;
-
- if let Some(ref mut back) = self.backiter {
- init = back.try_fold(init, &mut fold)?;
- }
- self.backiter = None;
-
- try { init }
+ self.iter_try_fold(init, flatten(fold))
}
#[inline]
- fn fold<Acc, Fold>(self, mut init: Acc, mut fold: Fold) -> Acc
+ fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
- fn flatten<T: IntoIterator, Acc>(
- fold: &mut impl FnMut(Acc, T::Item) -> Acc,
- ) -> impl FnMut(Acc, T) -> Acc + '_ {
- move |acc, x| x.into_iter().fold(acc, &mut *fold)
- }
-
- if let Some(front) = self.frontiter {
- init = front.fold(init, &mut fold);
- }
-
- init = self.iter.fold(init, flatten(&mut fold));
-
- if let Some(back) = self.backiter {
- init = back.fold(init, &mut fold);
+ fn flatten<U: Iterator, Acc>(
+ mut fold: impl FnMut(Acc, U::Item) -> Acc,
+ ) -> impl FnMut(Acc, U) -> Acc {
+ move |acc, iter| iter.fold(acc, &mut fold)
}
- init
+ self.iter_fold(init, flatten(fold))
}
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
- let mut rem = n;
- loop {
- if let Some(ref mut front) = self.frontiter {
- match front.advance_by(rem) {
- ret @ Ok(_) => return ret,
- Err(advanced) => rem -= advanced,
- }
- }
- self.frontiter = match self.iter.next() {
- Some(iterable) => Some(iterable.into_iter()),
- _ => break,
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
+ match iter.advance_by(n) {
+ Ok(()) => ControlFlow::BREAK,
+ Err(advanced) => ControlFlow::Continue(n - advanced),
}
}
- self.frontiter = None;
-
- if let Some(ref mut back) = self.backiter {
- match back.advance_by(rem) {
- ret @ Ok(_) => return ret,
- Err(advanced) => rem -= advanced,
- }
+ match self.iter_try_fold(n, advance) {
+ ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
+ _ => Ok(()),
}
+ }
- if rem > 0 {
- return Err(n - rem);
+ #[inline]
+ fn count(self) -> usize {
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ fn count<U: Iterator>(acc: usize, iter: U) -> usize {
+ acc + iter.count()
}
- self.backiter = None;
+ self.iter_fold(0, count)
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ #[inline]
+ fn last<U: Iterator>(last: Option<U::Item>, iter: U) -> Option<U::Item> {
+ iter.last().or(last)
+ }
- Ok(())
+ self.iter_fold(None, last)
}
}
@@ -438,105 +591,53 @@ where
}
#[inline]
- fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Output = Acc>,
{
#[inline]
- fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>(
- backiter: &'a mut Option<T::IntoIter>,
- fold: &'a mut impl FnMut(Acc, T::Item) -> R,
- ) -> impl FnMut(Acc, T) -> R + 'a
- where
- T::IntoIter: DoubleEndedIterator,
- {
- move |acc, x| {
- let mut mid = x.into_iter();
- let r = mid.try_rfold(acc, &mut *fold);
- *backiter = Some(mid);
- r
- }
+ fn flatten<U: DoubleEndedIterator, Acc, R: Try<Output = Acc>>(
+ mut fold: impl FnMut(Acc, U::Item) -> R,
+ ) -> impl FnMut(Acc, &mut U) -> R {
+ move |acc, iter| iter.try_rfold(acc, &mut fold)
}
- if let Some(ref mut back) = self.backiter {
- init = back.try_rfold(init, &mut fold)?;
- }
- self.backiter = None;
-
- init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
- self.backiter = None;
-
- if let Some(ref mut front) = self.frontiter {
- init = front.try_rfold(init, &mut fold)?;
- }
- self.frontiter = None;
-
- try { init }
+ self.iter_try_rfold(init, flatten(fold))
}
#[inline]
- fn rfold<Acc, Fold>(self, mut init: Acc, mut fold: Fold) -> Acc
+ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
#[inline]
- fn flatten<T: IntoIterator, Acc>(
- fold: &mut impl FnMut(Acc, T::Item) -> Acc,
- ) -> impl FnMut(Acc, T) -> Acc + '_
- where
- T::IntoIter: DoubleEndedIterator,
- {
- move |acc, x| x.into_iter().rfold(acc, &mut *fold)
- }
-
- if let Some(back) = self.backiter {
- init = back.rfold(init, &mut fold);
+ fn flatten<U: DoubleEndedIterator, Acc>(
+ mut fold: impl FnMut(Acc, U::Item) -> Acc,
+ ) -> impl FnMut(Acc, U) -> Acc {
+ move |acc, iter| iter.rfold(acc, &mut fold)
}
- init = self.iter.rfold(init, flatten(&mut fold));
-
- if let Some(front) = self.frontiter {
- init = front.rfold(init, &mut fold);
- }
-
- init
+ self.iter_rfold(init, flatten(fold))
}
#[inline]
#[rustc_inherit_overflow_checks]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
- let mut rem = n;
- loop {
- if let Some(ref mut back) = self.backiter {
- match back.advance_back_by(rem) {
- ret @ Ok(_) => return ret,
- Err(advanced) => rem -= advanced,
- }
- }
- match self.iter.next_back() {
- Some(iterable) => self.backiter = Some(iterable.into_iter()),
- _ => break,
- }
- }
-
- self.backiter = None;
-
- if let Some(ref mut front) = self.frontiter {
- match front.advance_back_by(rem) {
- ret @ Ok(_) => return ret,
- Err(advanced) => rem -= advanced,
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
+ match iter.advance_back_by(n) {
+ Ok(()) => ControlFlow::BREAK,
+ Err(advanced) => ControlFlow::Continue(n - advanced),
}
}
- if rem > 0 {
- return Err(n - rem);
+ match self.iter_try_rfold(n, advance) {
+ ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
+ _ => Ok(()),
}
-
- self.frontiter = None;
-
- Ok(())
}
}
diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs
index 1e8d6bf3e..fbdeca4d4 100644
--- a/library/core/src/iter/adapters/map_while.rs
+++ b/library/core/src/iter/adapters/map_while.rs
@@ -64,19 +64,7 @@ where
.into_try()
}
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
}
#[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 916a26e24..8cc2b7cec 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -1,6 +1,7 @@
use crate::iter::{InPlaceIterable, Iterator};
-use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try};
+use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
+mod array_chunks;
mod by_ref_sized;
mod chain;
mod cloned;
@@ -32,6 +33,9 @@ pub use self::{
scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip,
};
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+pub use self::array_chunks::ArrayChunks;
+
#[unstable(feature = "std_internals", issue = "none")]
pub use self::by_ref_sized::ByRefSized;
@@ -199,13 +203,7 @@ where
.into_try()
}
- fn fold<B, F>(mut self, init: B, fold: F) -> B
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> B,
- {
- self.try_fold(init, NeverShortCircuit::wrap_mut_2(fold)).0
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
}
#[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs
index 80bfd2231..62470512c 100644
--- a/library/core/src/iter/adapters/scan.rs
+++ b/library/core/src/iter/adapters/scan.rs
@@ -74,19 +74,7 @@ where
self.iter.try_fold(init, scan(state, f, fold)).into_try()
}
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
}
#[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index 2c283100f..c6334880d 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -33,21 +33,32 @@ where
#[inline]
fn next(&mut self) -> Option<I::Item> {
if unlikely(self.n > 0) {
- self.iter.nth(crate::mem::take(&mut self.n) - 1)?;
+ self.iter.nth(crate::mem::take(&mut self.n))
+ } else {
+ self.iter.next()
}
- self.iter.next()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
- // Can't just add n + self.n due to overflow.
if self.n > 0 {
- let to_skip = self.n;
- self.n = 0;
- // nth(n) skips n+1
- self.iter.nth(to_skip - 1)?;
+ let skip: usize = crate::mem::take(&mut self.n);
+ // Checked add to handle overflow case.
+ let n = match skip.checked_add(n) {
+ Some(nth) => nth,
+ None => {
+ // In case of overflow, load skip value, before loading `n`.
+ // Because the amount of elements to iterate is beyond `usize::MAX`, this
+ // is split into two `nth` calls where the `skip` `nth` call is discarded.
+ self.iter.nth(skip - 1)?;
+ n
+ }
+ };
+ // Load nth element including skip.
+ self.iter.nth(n)
+ } else {
+ self.iter.nth(n)
}
- self.iter.nth(n)
}
#[inline]
@@ -195,17 +206,7 @@ where
if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
}
- fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<Acc, T>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, T) -> Result<Acc, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_rfold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { rfold -> try_rfold }
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index 2962e0104..58a0b9d7b 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -98,19 +98,7 @@ where
}
}
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
#[inline]
#[rustc_inherit_overflow_checks]
diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs
index ded216da9..ec66dc3ae 100644
--- a/library/core/src/iter/adapters/take_while.rs
+++ b/library/core/src/iter/adapters/take_while.rs
@@ -94,19 +94,7 @@ where
}
}
- #[inline]
- fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
- where
- Self: Sized,
- Fold: FnMut(Acc, Self::Item) -> Acc,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(fold)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
}
#[stable(feature = "fused", since = "1.26.0")]
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index d5c6aed5b..ef0f39782 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -352,6 +352,29 @@
#![stable(feature = "rust1", since = "1.0.0")]
+// This needs to be up here in order to be usable in the child modules
+macro_rules! impl_fold_via_try_fold {
+ (fold -> try_fold) => {
+ impl_fold_via_try_fold! { @internal fold -> try_fold }
+ };
+ (rfold -> try_rfold) => {
+ impl_fold_via_try_fold! { @internal rfold -> try_rfold }
+ };
+ (@internal $fold:ident -> $try_fold:ident) => {
+ #[inline]
+ fn $fold<AAA, FFF>(mut self, init: AAA, mut fold: FFF) -> AAA
+ where
+ FFF: FnMut(AAA, Self::Item) -> AAA,
+ {
+ use crate::const_closure::ConstFnMutClosure;
+ use crate::ops::NeverShortCircuit;
+
+ let fold = ConstFnMutClosure::new(&mut fold, NeverShortCircuit::wrap_mut_2_imp);
+ self.$try_fold(init, fold).0
+ }
+ };
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::traits::Iterator;
@@ -398,6 +421,8 @@ pub use self::traits::{
#[stable(feature = "iter_zip", since = "1.59.0")]
pub use self::adapters::zip;
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+pub use self::adapters::ArrayChunks;
#[unstable(feature = "std_internals", issue = "none")]
pub use self::adapters::ByRefSized;
#[stable(feature = "iter_cloned", since = "1.1.0")]
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index f7aeee8c9..ac7b389b1 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -1150,19 +1150,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
self.spec_try_fold(init, f)
}
- #[inline]
- fn fold<B, F>(mut self, init: B, f: F) -> B
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> B,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_fold(init, ok(f)).unwrap()
- }
+ impl_fold_via_try_fold! { fold -> try_fold }
#[inline]
fn last(mut self) -> Option<A> {
@@ -1230,19 +1218,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
self.spec_try_rfold(init, f)
}
- #[inline]
- fn rfold<B, F>(mut self, init: B, f: F) -> B
- where
- Self: Sized,
- F: FnMut(B, Self::Item) -> B,
- {
- #[inline]
- fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
- move |acc, x| Ok(f(acc, x))
- }
-
- self.try_rfold(init, ok(f)).unwrap()
- }
+ impl_fold_via_try_fold! { rfold -> try_rfold }
}
// Safety: See above implementation for `ops::Range<A>`
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 12ca508be..e099700e3 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -228,6 +228,7 @@ pub trait FromIterator<A>: Sized {
#[rustc_diagnostic_item = "IntoIterator"]
#[rustc_skip_array_during_method_dispatch]
#[stable(feature = "rust1", since = "1.0.0")]
+#[const_trait]
pub trait IntoIterator {
/// The type of the elements being iterated over.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -263,7 +264,7 @@ pub trait IntoIterator {
#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")]
#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: ~const Iterator> const IntoIterator for I {
+impl<I: Iterator> const IntoIterator for I {
type Item = I::Item;
type IntoIter = I;
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 275412b57..789a87968 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -5,7 +5,7 @@ use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
use super::super::try_process;
use super::super::ByRefSized;
use super::super::TrustedRandomAccessNoCoerce;
-use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
+use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
use super::super::{FlatMap, Flatten};
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
use super::super::{
@@ -692,7 +692,7 @@ pub trait Iterator {
/// assert_eq!(it.next(), Some(NotClone(99))); // The separator.
/// assert_eq!(it.next(), Some(NotClone(1))); // The next element from `v`.
/// assert_eq!(it.next(), Some(NotClone(99))); // The separator.
- /// assert_eq!(it.next(), Some(NotClone(2))); // The last element from from `v`.
+ /// assert_eq!(it.next(), Some(NotClone(2))); // The last element from `v`.
/// assert_eq!(it.next(), None); // The iterator is finished.
/// ```
///
@@ -2431,22 +2431,13 @@ pub trait Iterator {
///
/// # Example
///
- /// Find the maximum value:
- ///
/// ```
- /// fn find_max<I>(iter: I) -> Option<I::Item>
- /// where I: Iterator,
- /// I::Item: Ord,
- /// {
- /// iter.reduce(|accum, item| {
- /// if accum >= item { accum } else { item }
- /// })
- /// }
- /// let a = [10, 20, 5, -23, 0];
- /// let b: [u32; 0] = [];
+ /// let reduced: i32 = (1..10).reduce(|acc, e| acc + e).unwrap();
+ /// assert_eq!(reduced, 45);
///
- /// assert_eq!(find_max(a.iter()), Some(&20));
- /// assert_eq!(find_max(b.iter()), None);
+ /// // Which is equivalent to doing it with `fold`:
+ /// let folded: i32 = (1..10).fold(0, |acc, e| acc + e);
+ /// assert_eq!(reduced, folded);
/// ```
#[inline]
#[stable(feature = "iterator_fold_self", since = "1.51.0")]
@@ -2906,14 +2897,14 @@ pub trait Iterator {
/// Stopping at the first `true`:
///
/// ```
- /// let a = [1, 2, 3];
+ /// let a = [-1, 2, 3, 4];
///
/// let mut iter = a.iter();
///
- /// assert_eq!(iter.rposition(|&x| x == 2), Some(1));
+ /// assert_eq!(iter.rposition(|&x| x >= 2), Some(3));
///
/// // we can still use `iter`, as there are more elements.
- /// assert_eq!(iter.next(), Some(&1));
+ /// assert_eq!(iter.next(), Some(&-1));
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -3316,6 +3307,49 @@ pub trait Iterator {
Cycle::new(self)
}
+ /// Returns an iterator over `N` elements of the iterator at a time.
+ ///
+ /// The chunks do not overlap. If `N` does not divide the length of the
+ /// iterator, then the last up to `N-1` elements will be omitted and can be
+ /// retrieved from the [`.into_remainder()`][ArrayChunks::into_remainder]
+ /// function of the iterator.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N` is 0.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(iter_array_chunks)]
+ ///
+ /// let mut iter = "lorem".chars().array_chunks();
+ /// assert_eq!(iter.next(), Some(['l', 'o']));
+ /// assert_eq!(iter.next(), Some(['r', 'e']));
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.into_remainder().unwrap().as_slice(), &['m']);
+ /// ```
+ ///
+ /// ```
+ /// #![feature(iter_array_chunks)]
+ ///
+ /// let data = [1, 1, 2, -2, 6, 0, 3, 1];
+ /// // ^-----^ ^------^
+ /// for [x, y, z] in data.iter().array_chunks() {
+ /// assert_eq!(x + y + z, 4);
+ /// }
+ /// ```
+ #[track_caller]
+ #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+ fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N>
+ where
+ Self: Sized,
+ {
+ ArrayChunks::new(self)
+ }
+
/// Sums the elements of an iterator.
///
/// Takes each element, adds them together, and returns the result.
@@ -3418,36 +3452,27 @@ pub trait Iterator {
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater);
/// ```
#[unstable(feature = "iter_order_by", issue = "64295")]
- fn cmp_by<I, F>(mut self, other: I, mut cmp: F) -> Ordering
+ fn cmp_by<I, F>(self, other: I, cmp: F) -> Ordering
where
Self: Sized,
I: IntoIterator,
F: FnMut(Self::Item, I::Item) -> Ordering,
{
- let mut other = other.into_iter();
-
- loop {
- let x = match self.next() {
- None => {
- if other.next().is_none() {
- return Ordering::Equal;
- } else {
- return Ordering::Less;
- }
- }
- Some(val) => val,
- };
-
- let y = match other.next() {
- None => return Ordering::Greater,
- Some(val) => val,
- };
-
- match cmp(x, y) {
- Ordering::Equal => (),
- non_eq => return non_eq,
+ #[inline]
+ fn compare<X, Y, F>(mut cmp: F) -> impl FnMut(X, Y) -> ControlFlow<Ordering>
+ where
+ F: FnMut(X, Y) -> Ordering,
+ {
+ move |x, y| match cmp(x, y) {
+ Ordering::Equal => ControlFlow::CONTINUE,
+ non_eq => ControlFlow::Break(non_eq),
}
}
+
+ match iter_compare(self, other.into_iter(), compare(cmp)) {
+ ControlFlow::Continue(ord) => ord,
+ ControlFlow::Break(ord) => ord,
+ }
}
/// [Lexicographically](Ord#lexicographical-comparison) compares the elements of this [`Iterator`] with those
@@ -3503,36 +3528,27 @@ pub trait Iterator {
/// );
/// ```
#[unstable(feature = "iter_order_by", issue = "64295")]
- fn partial_cmp_by<I, F>(mut self, other: I, mut partial_cmp: F) -> Option<Ordering>
+ fn partial_cmp_by<I, F>(self, other: I, partial_cmp: F) -> Option<Ordering>
where
Self: Sized,
I: IntoIterator,
F: FnMut(Self::Item, I::Item) -> Option<Ordering>,
{
- let mut other = other.into_iter();
-
- loop {
- let x = match self.next() {
- None => {
- if other.next().is_none() {
- return Some(Ordering::Equal);
- } else {
- return Some(Ordering::Less);
- }
- }
- Some(val) => val,
- };
-
- let y = match other.next() {
- None => return Some(Ordering::Greater),
- Some(val) => val,
- };
-
- match partial_cmp(x, y) {
- Some(Ordering::Equal) => (),
- non_eq => return non_eq,
+ #[inline]
+ fn compare<X, Y, F>(mut partial_cmp: F) -> impl FnMut(X, Y) -> ControlFlow<Option<Ordering>>
+ where
+ F: FnMut(X, Y) -> Option<Ordering>,
+ {
+ move |x, y| match partial_cmp(x, y) {
+ Some(Ordering::Equal) => ControlFlow::CONTINUE,
+ non_eq => ControlFlow::Break(non_eq),
}
}
+
+ match iter_compare(self, other.into_iter(), compare(partial_cmp)) {
+ ControlFlow::Continue(ord) => Some(ord),
+ ControlFlow::Break(ord) => ord,
+ }
}
/// Determines if the elements of this [`Iterator`] are equal to those of
@@ -3570,29 +3586,26 @@ pub trait Iterator {
/// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y));
/// ```
#[unstable(feature = "iter_order_by", issue = "64295")]
- fn eq_by<I, F>(mut self, other: I, mut eq: F) -> bool
+ fn eq_by<I, F>(self, other: I, eq: F) -> bool
where
Self: Sized,
I: IntoIterator,
F: FnMut(Self::Item, I::Item) -> bool,
{
- let mut other = other.into_iter();
-
- loop {
- let x = match self.next() {
- None => return other.next().is_none(),
- Some(val) => val,
- };
-
- let y = match other.next() {
- None => return false,
- Some(val) => val,
- };
-
- if !eq(x, y) {
- return false;
+ #[inline]
+ fn compare<X, Y, F>(mut eq: F) -> impl FnMut(X, Y) -> ControlFlow<()>
+ where
+ F: FnMut(X, Y) -> bool,
+ {
+ move |x, y| {
+ if eq(x, y) { ControlFlow::CONTINUE } else { ControlFlow::BREAK }
}
}
+
+ match iter_compare(self, other.into_iter(), compare(eq)) {
+ ControlFlow::Continue(ord) => ord == Ordering::Equal,
+ ControlFlow::Break(()) => false,
+ }
}
/// Determines if the elements of this [`Iterator`] are unequal to those of
@@ -3817,6 +3830,46 @@ pub trait Iterator {
}
}
+/// Compares two iterators element-wise using the given function.
+///
+/// If `ControlFlow::CONTINUE` is returned from the function, the comparison moves on to the next
+/// elements of both iterators. Returning `ControlFlow::Break(x)` short-circuits the iteration and
+/// returns `ControlFlow::Break(x)`. If one of the iterators runs out of elements,
+/// `ControlFlow::Continue(ord)` is returned where `ord` is the result of comparing the lengths of
+/// the iterators.
+///
+/// Isolates the logic shared by ['cmp_by'](Iterator::cmp_by),
+/// ['partial_cmp_by'](Iterator::partial_cmp_by), and ['eq_by'](Iterator::eq_by).
+#[inline]
+fn iter_compare<A, B, F, T>(mut a: A, mut b: B, f: F) -> ControlFlow<T, Ordering>
+where
+ A: Iterator,
+ B: Iterator,
+ F: FnMut(A::Item, B::Item) -> ControlFlow<T>,
+{
+ #[inline]
+ fn compare<'a, B, X, T>(
+ b: &'a mut B,
+ mut f: impl FnMut(X, B::Item) -> ControlFlow<T> + 'a,
+ ) -> impl FnMut(X) -> ControlFlow<ControlFlow<T, Ordering>> + 'a
+ where
+ B: Iterator,
+ {
+ move |x| match b.next() {
+ None => ControlFlow::Break(ControlFlow::Continue(Ordering::Greater)),
+ Some(y) => f(x, y).map_break(ControlFlow::Break),
+ }
+ }
+
+ match a.try_for_each(compare(&mut b, f)) {
+ ControlFlow::Continue(()) => ControlFlow::Continue(match b.next() {
+ None => Ordering::Equal,
+ Some(_) => Ordering::Less,
+ }),
+ ControlFlow::Break(x) => x,
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator + ?Sized> Iterator for &mut I {
type Item = I::Item;
diff --git a/library/core/src/lazy.rs b/library/core/src/lazy.rs
deleted file mode 100644
index f8c06c3f9..000000000
--- a/library/core/src/lazy.rs
+++ /dev/null
@@ -1 +0,0 @@
-//! Lazy values and one-time initialization of static data.
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 24742bb49..659409557 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -93,6 +93,7 @@
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![allow(explicit_outlives_requirements)]
+#![allow(incomplete_features)]
//
// Library features:
#![feature(const_align_offset)]
@@ -113,6 +114,7 @@
#![feature(const_fmt_arguments_new)]
#![feature(const_heap)]
#![feature(const_convert)]
+#![feature(const_index_range_slice_index)]
#![feature(const_inherent_unchecked_arith)]
#![feature(const_int_unchecked_arith)]
#![feature(const_intrinsic_forget)]
@@ -130,25 +132,30 @@
#![feature(const_replace)]
#![feature(const_ptr_as_ref)]
#![feature(const_ptr_is_null)]
-#![feature(const_ptr_offset_from)]
#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
#![feature(const_raw_ptr_comparison)]
#![feature(const_size_of_val)]
#![feature(const_slice_from_raw_parts_mut)]
#![feature(const_slice_ptr_len)]
+#![feature(const_slice_split_at_mut)]
#![feature(const_str_from_utf8_unchecked_mut)]
#![feature(const_swap)]
#![feature(const_trait_impl)]
+#![feature(const_try)]
#![feature(const_type_id)]
#![feature(const_type_name)]
#![feature(const_default_impls)]
+#![feature(const_unicode_case_lookup)]
#![feature(const_unsafecell_get_mut)]
+#![feature(const_waker)]
#![feature(core_panic)]
#![feature(duration_consts_float)]
#![feature(maybe_uninit_uninit_array)]
+#![feature(ptr_alignment_type)]
#![feature(ptr_metadata)]
#![feature(slice_ptr_get)]
+#![feature(slice_split_at_unchecked)]
#![feature(str_internals)]
#![feature(utf16_extra)]
#![feature(utf16_extra_const)]
@@ -157,13 +164,17 @@
#![feature(const_slice_from_ref)]
#![feature(const_slice_index)]
#![feature(const_is_char_boundary)]
+#![feature(const_cstr_methods)]
+#![feature(is_ascii_octdigit)]
//
// Language features:
#![feature(abi_unadjusted)]
+#![feature(adt_const_params)]
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
+#![feature(c_unwind)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
#![feature(cfg_target_has_atomic_equal_alignment)]
@@ -181,13 +192,13 @@
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(if_let_guard)]
+#![feature(inline_const)]
#![feature(intra_doc_pointers)]
#![feature(intrinsics)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
#![feature(macro_metavar_expr)]
#![feature(min_specialization)]
-#![feature(mixed_integer_ops)]
#![feature(must_not_suspend)]
#![feature(negative_impls)]
#![feature(never_type)]
@@ -201,12 +212,14 @@
#![feature(simd_ffi)]
#![feature(staged_api)]
#![feature(stmt_expr_attributes)]
+#![feature(target_feature_11)]
#![feature(trait_alias)]
#![feature(transparent_unions)]
#![feature(try_blocks)]
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
#![feature(asm_const)]
+#![feature(const_transmute_copy)]
//
// Target features:
#![feature(arm_target_feature)]
@@ -216,6 +229,7 @@
#![feature(hexagon_target_feature)]
#![feature(mips_target_feature)]
#![feature(powerpc_target_feature)]
+#![feature(riscv_target_feature)]
#![feature(rtm_target_feature)]
#![feature(sse4a_target_feature)]
#![feature(tbm_target_feature)]
@@ -302,6 +316,7 @@ pub mod clone;
pub mod cmp;
pub mod convert;
pub mod default;
+pub mod error;
pub mod marker;
pub mod ops;
@@ -317,8 +332,6 @@ pub mod cell;
pub mod char;
pub mod ffi;
pub mod iter;
-#[unstable(feature = "once_cell", issue = "74465")]
-pub mod lazy;
pub mod option;
pub mod panic;
pub mod panicking;
@@ -347,6 +360,8 @@ mod bool;
mod tuple;
mod unit;
+mod const_closure;
+
#[stable(feature = "core_primitive", since = "1.43.0")]
pub mod primitive;
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 3a115a8b8..fd96e1ff7 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -350,10 +350,12 @@ macro_rules! matches {
/// Unwraps a result or propagates its error.
///
-/// The `?` operator was added to replace `try!` and should be used instead.
-/// Furthermore, `try` is a reserved word in Rust 2018, so if you must use
-/// it, you will need to use the [raw-identifier syntax][ris]: `r#try`.
+/// The [`?` operator][propagating-errors] was added to replace `try!`
+/// and should be used instead. Furthermore, `try` is a reserved word
+/// in Rust 2018, so if you must use it, you will need to use the
+/// [raw-identifier syntax][ris]: `r#try`.
///
+/// [propagating-errors]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
/// [ris]: https://doc.rust-lang.org/nightly/rust-by-example/compatibility/raw_identifiers.html
///
/// `try!` matches the given [`Result`]. In case of the `Ok` variant, the
@@ -457,11 +459,12 @@ macro_rules! r#try {
///
/// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects
/// implementing either, as objects do not typically implement both. However, the module must
-/// import the traits qualified so their names do not conflict:
+/// avoid conflict between the trait names, such as by importing them as `_` or otherwise renaming
+/// them:
///
/// ```
-/// use std::fmt::Write as FmtWrite;
-/// use std::io::Write as IoWrite;
+/// use std::fmt::Write as _;
+/// use std::io::Write as _;
///
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut s = String::new();
@@ -474,6 +477,23 @@ macro_rules! r#try {
/// }
/// ```
///
+/// If you also need the trait names themselves, such as to implement one or both on your types,
+/// import the containing module and then name them with a prefix:
+///
+/// ```
+/// # #![allow(unused_imports)]
+/// use std::fmt::{self, Write as _};
+/// use std::io::{self, Write as _};
+///
+/// struct Example;
+///
+/// impl fmt::Write for Example {
+/// fn write_str(&mut self, _s: &str) -> core::fmt::Result {
+/// unimplemented!();
+/// }
+/// }
+/// ```
+///
/// Note: This macro can be used in `no_std` setups as well.
/// In a `no_std` setup you are responsible for the implementation details of the components.
///
@@ -526,25 +546,6 @@ macro_rules! write {
/// Ok(())
/// }
/// ```
-///
-/// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects
-/// implementing either, as objects do not typically implement both. However, the module must
-/// import the traits qualified so their names do not conflict:
-///
-/// ```
-/// use std::fmt::Write as FmtWrite;
-/// use std::io::Write as IoWrite;
-///
-/// fn main() -> Result<(), Box<dyn std::error::Error>> {
-/// let mut s = String::new();
-/// let mut v = Vec::new();
-///
-/// writeln!(&mut s, "{} {}", "abc", 123)?; // uses fmt::Write::write_fmt
-/// writeln!(&mut v, "s = {:?}", s)?; // uses io::Write::write_fmt
-/// assert_eq!(v, b"s = \"abc 123\\n\"\n");
-/// Ok(())
-/// }
-/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "writeln_macro")]
@@ -1015,7 +1016,7 @@ pub(crate) mod builtin {
/// Concatenates literals into a byte slice.
///
/// This macro takes any number of comma-separated literals, and concatenates them all into
- /// one, yielding an expression of type `&[u8, _]`, which represents all of the literals
+ /// one, yielding an expression of type `&[u8; _]`, which represents all of the literals
/// concatenated left-to-right. The literals passed can be any combination of:
///
/// - byte literals (`b'r'`)
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 2c5789795..ae4ebf444 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -44,6 +44,12 @@ impl<T: ?Sized> !Send for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Send for *mut T {}
+// Most instances arise automatically, but this instance is needed to link up `T: Sync` with
+// `&T: Send` (and it also removes the unsound default instance `T Send` -> `&T: Send` that would
+// otherwise exist).
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync + ?Sized> Send for &T {}
+
/// Types with a constant size known at compile time.
///
/// All type parameters have an implicit bound of `Sized`. The special syntax
@@ -81,6 +87,7 @@ impl<T: ?Sized> !Send for *mut T {}
/// ```
///
/// [trait object]: ../../book/ch17-02-trait-objects.html
+#[doc(alias = "?", alias = "?Sized")]
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sized"]
#[rustc_on_unimplemented(
@@ -343,7 +350,7 @@ pub trait StructuralEq {
/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get
/// the error [E0204].
///
-/// [E0204]: ../../error-index.html#E0204
+/// [E0204]: ../../error_codes/E0204.html
///
/// ## When *should* my type be `Copy`?
///
@@ -482,64 +489,6 @@ impl<T: ?Sized> !Sync for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Sync for *mut T {}
-macro_rules! impls {
- ($t: ident) => {
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> Hash for $t<T> {
- #[inline]
- fn hash<H: Hasher>(&self, _: &mut H) {}
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> cmp::PartialEq for $t<T> {
- fn eq(&self, _other: &$t<T>) -> bool {
- true
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> cmp::Eq for $t<T> {}
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> cmp::PartialOrd for $t<T> {
- fn partial_cmp(&self, _other: &$t<T>) -> Option<cmp::Ordering> {
- Option::Some(cmp::Ordering::Equal)
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> cmp::Ord for $t<T> {
- fn cmp(&self, _other: &$t<T>) -> cmp::Ordering {
- cmp::Ordering::Equal
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> Copy for $t<T> {}
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T: ?Sized> Clone for $t<T> {
- fn clone(&self) -> Self {
- Self
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
- impl<T: ?Sized> const Default for $t<T> {
- fn default() -> Self {
- Self
- }
- }
-
- #[unstable(feature = "structural_match", issue = "31434")]
- impl<T: ?Sized> StructuralPartialEq for $t<T> {}
-
- #[unstable(feature = "structural_match", issue = "31434")]
- impl<T: ?Sized> StructuralEq for $t<T> {}
- };
-}
-
/// Zero-sized type used to mark things that "act like" they own a `T`.
///
/// Adding a `PhantomData<T>` field to your type tells the compiler that your
@@ -677,15 +626,60 @@ macro_rules! impls {
#[stable(feature = "rust1", since = "1.0.0")]
pub struct PhantomData<T: ?Sized>;
-impls! { PhantomData }
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Hash for PhantomData<T> {
+ #[inline]
+ fn hash<H: Hasher>(&self, _: &mut H) {}
+}
-mod impls {
- #[stable(feature = "rust1", since = "1.0.0")]
- unsafe impl<T: Sync + ?Sized> Send for &T {}
- #[stable(feature = "rust1", since = "1.0.0")]
- unsafe impl<T: Send + ?Sized> Send for &mut T {}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> cmp::PartialEq for PhantomData<T> {
+ fn eq(&self, _other: &PhantomData<T>) -> bool {
+ true
+ }
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> cmp::Eq for PhantomData<T> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> cmp::PartialOrd for PhantomData<T> {
+ fn partial_cmp(&self, _other: &PhantomData<T>) -> Option<cmp::Ordering> {
+ Option::Some(cmp::Ordering::Equal)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> cmp::Ord for PhantomData<T> {
+ fn cmp(&self, _other: &PhantomData<T>) -> cmp::Ordering {
+ cmp::Ordering::Equal
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Copy for PhantomData<T> {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Clone for PhantomData<T> {
+ fn clone(&self) -> Self {
+ Self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+impl<T: ?Sized> const Default for PhantomData<T> {
+ fn default() -> Self {
+ Self
+ }
+}
+
+#[unstable(feature = "structural_match", issue = "31434")]
+impl<T: ?Sized> StructuralPartialEq for PhantomData<T> {}
+
+#[unstable(feature = "structural_match", issue = "31434")]
+impl<T: ?Sized> StructuralEq for PhantomData<T> {}
+
/// Compiler-internal trait used to indicate the type of enum discriminants.
///
/// This trait is automatically implemented for every type and does not add any
@@ -798,8 +792,18 @@ impl<T: ?Sized> Unpin for *mut T {}
#[unstable(feature = "const_trait_impl", issue = "67792")]
#[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
+#[const_trait]
pub trait Destruct {}
+/// A marker for tuple types.
+///
+/// The implementation of this trait is built-in and cannot be implemented
+/// for any user type.
+#[unstable(feature = "tuple_trait", issue = "none")]
+#[lang = "tuple_trait"]
+#[rustc_on_unimplemented(message = "`{Self}` is not a tuple")]
+pub trait Tuple {}
+
/// Implementations of `Copy` for primitive types.
///
/// Implementations that cannot be described in Rust
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index b4ea53608..7757c95de 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -54,9 +54,6 @@ use crate::slice;
/// // The equivalent code with `MaybeUninit<i32>`:
/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️
/// ```
-/// (Notice that the rules around uninitialized integers are not finalized yet, but
-/// until they are, it is advisable to avoid them.)
-///
/// On top of that, remember that most types have additional invariants beyond merely
/// being considered initialized at the type level. For example, a `1`-initialized [`Vec<T>`]
/// is considered initialized (under the current implementation; this does not constitute
@@ -130,11 +127,8 @@ use crate::slice;
/// MaybeUninit::uninit().assume_init()
/// };
///
-/// // Dropping a `MaybeUninit` does nothing. Thus using raw pointer
-/// // assignment instead of `ptr::write` does not cause the old
-/// // uninitialized value to be dropped. Also if there is a panic during
-/// // this loop, we have a memory leak, but there is no memory safety
-/// // issue.
+/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop,
+/// // we have a memory leak, but there is no memory safety issue.
/// for elem in &mut data[..] {
/// elem.write(vec![42]);
/// }
@@ -152,7 +146,6 @@ use crate::slice;
///
/// ```
/// use std::mem::MaybeUninit;
-/// use std::ptr;
///
/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
/// // safe because the type we are claiming to have initialized here is a
@@ -168,7 +161,7 @@ use crate::slice;
///
/// // For each item in the array, drop if we allocated it.
/// for elem in &mut data[0..data_len] {
-/// unsafe { ptr::drop_in_place(elem.as_mut_ptr()); }
+/// unsafe { elem.assume_init_drop(); }
/// }
/// ```
///
@@ -653,7 +646,7 @@ impl<T> MaybeUninit<T> {
/// implements the [`Copy`] trait or not. When using multiple copies of the
/// data (by calling `assume_init_read` multiple times, or first calling
/// `assume_init_read` and then [`assume_init`]), it is your responsibility
- /// to ensure that that data may indeed be duplicated.
+ /// to ensure that data may indeed be duplicated.
///
/// [inv]: #initialization-invariant
/// [`assume_init`]: MaybeUninit::assume_init
@@ -1290,3 +1283,42 @@ impl<T> MaybeUninit<T> {
}
}
}
+
+impl<T, const N: usize> MaybeUninit<[T; N]> {
+ /// Transposes a `MaybeUninit<[T; N]>` into a `[MaybeUninit<T>; N]`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(maybe_uninit_uninit_array_transpose)]
+ /// # use std::mem::MaybeUninit;
+ ///
+ /// let data: [MaybeUninit<u8>; 1000] = MaybeUninit::uninit().transpose();
+ /// ```
+ #[unstable(feature = "maybe_uninit_uninit_array_transpose", issue = "96097")]
+ #[inline]
+ pub const fn transpose(self) -> [MaybeUninit<T>; N] {
+ // SAFETY: T and MaybeUninit<T> have the same layout
+ unsafe { super::transmute_copy(&ManuallyDrop::new(self)) }
+ }
+}
+
+impl<T, const N: usize> [MaybeUninit<T>; N] {
+ /// Transposes a `[MaybeUninit<T>; N]` into a `MaybeUninit<[T; N]>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(maybe_uninit_uninit_array_transpose)]
+ /// # use std::mem::MaybeUninit;
+ ///
+ /// let data = [MaybeUninit::<u8>::uninit(); 1000];
+ /// let data: MaybeUninit<[u8; 1000]> = data.transpose();
+ /// ```
+ #[unstable(feature = "maybe_uninit_uninit_array_transpose", issue = "96097")]
+ #[inline]
+ pub const fn transpose(self) -> MaybeUninit<[T; N]> {
+ // SAFETY: T and MaybeUninit<T> have the same layout
+ unsafe { super::transmute_copy(&ManuallyDrop::new(self)) }
+ }
+}
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 20b2d5e26..9195da5a4 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -21,11 +21,10 @@ mod maybe_uninit;
#[stable(feature = "maybe_uninit", since = "1.36.0")]
pub use maybe_uninit::MaybeUninit;
-mod valid_align;
-// For now this type is left crate-local. It could potentially make sense to expose
-// it publicly, as it would be a nice parameter type for methods which need to take
-// alignment as a parameter, such as `Layout::padding_needed_for`.
-pub(crate) use valid_align::ValidAlign;
+// FIXME: This is left here for now to avoid complications around pending reverts.
+// Once <https://github.com/rust-lang/rust/issues/101899> is fully resolved,
+// this should be removed and the references in `alloc::Layout` updated.
+pub(crate) use ptr::Alignment as ValidAlign;
mod transmutability;
#[unstable(feature = "transmutability", issue = "99571")]
@@ -665,14 +664,14 @@ pub unsafe fn zeroed<T>() -> T {
/// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit].
/// As the [`assume_init` documentation][assume_init] explains,
/// [the Rust compiler assumes][inv] that values are properly initialized.
-/// As a consequence, calling e.g. `mem::uninitialized::<bool>()` causes immediate
-/// undefined behavior for returning a `bool` that is not definitely either `true`
-/// or `false`. Worse, truly uninitialized memory like what gets returned here
+///
+/// Truly uninitialized memory like what gets returned here
/// is special in that the compiler knows that it does not have a fixed value.
/// This makes it undefined behavior to have uninitialized data in a variable even
/// if that variable has an integer type.
-/// (Notice that the rules around uninitialized integers are not finalized yet, but
-/// until they are, it is advisable to avoid them.)
+///
+/// Therefore, it is immediate undefined behavior to call this function on nearly all types,
+/// including integer types and arrays of integer types, and even if the result is unused.
///
/// [uninit]: MaybeUninit::uninit
/// [assume_init]: MaybeUninit::assume_init
@@ -1009,18 +1008,18 @@ pub fn copy<T: Copy>(x: &T) -> T {
*x
}
-/// Interprets `src` as having type `&U`, and then reads `src` without moving
+/// Interprets `src` as having type `&Dst`, and then reads `src` without moving
/// the contained value.
///
-/// This function will unsafely assume the pointer `src` is valid for [`size_of::<U>`][size_of]
-/// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way
-/// that is correct even when `&U` has stricter alignment requirements than `&T`). It will also
-/// unsafely create a copy of the contained value instead of moving out of `src`.
+/// This function will unsafely assume the pointer `src` is valid for [`size_of::<Dst>`][size_of]
+/// bytes by transmuting `&Src` to `&Dst` and then reading the `&Dst` (except that this is done
+/// in a way that is correct even when `&Dst` has stricter alignment requirements than `&Src`).
+/// It will also unsafely create a copy of the contained value instead of moving out of `src`.
///
-/// It is not a compile-time error if `T` and `U` have different sizes, but it
-/// is highly encouraged to only invoke this function where `T` and `U` have the
-/// same size. This function triggers [undefined behavior][ub] if `U` is larger than
-/// `T`.
+/// It is not a compile-time error if `Src` and `Dst` have different sizes, but it
+/// is highly encouraged to only invoke this function where `Src` and `Dst` have the
+/// same size. This function triggers [undefined behavior][ub] if `Dst` is larger than
+/// `Src`.
///
/// [ub]: ../../reference/behavior-considered-undefined.html
///
@@ -1053,19 +1052,22 @@ pub fn copy<T: Copy>(x: &T) -> T {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
-pub const unsafe fn transmute_copy<T, U>(src: &T) -> U {
- assert!(size_of::<T>() >= size_of::<U>(), "cannot transmute_copy if U is larger than T");
+pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst {
+ assert!(
+ size_of::<Src>() >= size_of::<Dst>(),
+ "cannot transmute_copy if Dst is larger than Src"
+ );
- // If U has a higher alignment requirement, src might not be suitably aligned.
- if align_of::<U>() > align_of::<T>() {
+ // If Dst has a higher alignment requirement, src might not be suitably aligned.
+ if align_of::<Dst>() > align_of::<Src>() {
// SAFETY: `src` is a reference which is guaranteed to be valid for reads.
// The caller must guarantee that the actual transmutation is safe.
- unsafe { ptr::read_unaligned(src as *const T as *const U) }
+ unsafe { ptr::read_unaligned(src as *const Src as *const Dst) }
} else {
// SAFETY: `src` is a reference which is guaranteed to be valid for reads.
- // We just checked that `src as *const U` was properly aligned.
+ // We just checked that `src as *const Dst` was properly aligned.
// The caller must guarantee that the actual transmutation is safe.
- unsafe { ptr::read(src as *const T as *const U) }
+ unsafe { ptr::read(src as *const Src as *const Dst) }
}
}
@@ -1178,3 +1180,44 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
pub const fn variant_count<T>() -> usize {
intrinsics::variant_count::<T>()
}
+
+/// Provides associated constants for various useful properties of types,
+/// to give them a canonical form in our code and make them easier to read.
+///
+/// This is here only to simplify all the ZST checks we need in the library.
+/// It's not on a stabilization track right now.
+#[doc(hidden)]
+#[unstable(feature = "sized_type_properties", issue = "none")]
+pub trait SizedTypeProperties: Sized {
+ /// `true` if this type requires no storage.
+ /// `false` if its [size](size_of) is greater than zero.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(sized_type_properties)]
+ /// use core::mem::SizedTypeProperties;
+ ///
+ /// fn do_something_with<T>() {
+ /// if T::IS_ZST {
+ /// // ... special approach ...
+ /// } else {
+ /// // ... the normal thing ...
+ /// }
+ /// }
+ ///
+ /// struct MyUnit;
+ /// assert!(MyUnit::IS_ZST);
+ ///
+ /// // For negative checks, consider using UFCS to emphasize the negation
+ /// assert!(!<i32>::IS_ZST);
+ /// // As it can sometimes hide in the type otherwise
+ /// assert!(!String::IS_ZST);
+ /// ```
+ #[doc(hidden)]
+ #[unstable(feature = "sized_type_properties", issue = "none")]
+ const IS_ZST: bool = size_of::<Self>() == 0;
+}
+#[doc(hidden)]
+#[unstable(feature = "sized_type_properties", issue = "none")]
+impl<T> SizedTypeProperties for T {}
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
index b59a5b89d..3b98efff2 100644
--- a/library/core/src/mem/transmutability.rs
+++ b/library/core/src/mem/transmutability.rs
@@ -4,25 +4,20 @@
/// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`,
/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
#[unstable(feature = "transmutability", issue = "99571")]
-#[cfg_attr(not(bootstrap), lang = "transmute_trait")]
+#[lang = "transmute_trait"]
#[rustc_on_unimplemented(
message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.",
label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`."
)]
-pub unsafe trait BikeshedIntrinsicFrom<
- Src,
- Context,
- const ASSUME_ALIGNMENT: bool,
- const ASSUME_LIFETIMES: bool,
- const ASSUME_VALIDITY: bool,
- const ASSUME_VISIBILITY: bool,
-> where
+pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }>
+where
Src: ?Sized,
{
}
/// What transmutation safety conditions shall the compiler assume that *you* are checking?
#[unstable(feature = "transmutability", issue = "99571")]
+#[lang = "transmute_opts"]
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct Assume {
/// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that
@@ -33,11 +28,80 @@ pub struct Assume {
/// that violates Rust's memory model.
pub lifetimes: bool,
+ /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the
+ /// type and field privacy of the destination type (and sometimes of the source type, too).
+ pub safety: bool,
+
/// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid
/// instance of the destination type.
pub validity: bool,
+}
- /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the
- /// type and field privacy of the destination type (and sometimes of the source type, too).
- pub visibility: bool,
+impl Assume {
+ /// Do not assume that *you* have ensured any safety properties are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const NOTHING: Self =
+ Self { alignment: false, lifetimes: false, safety: false, validity: false };
+
+ /// Assume only that alignment conditions are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const ALIGNMENT: Self = Self { alignment: true, ..Self::NOTHING };
+
+ /// Assume only that lifetime conditions are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const LIFETIMES: Self = Self { lifetimes: true, ..Self::NOTHING };
+
+ /// Assume only that safety conditions are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const SAFETY: Self = Self { safety: true, ..Self::NOTHING };
+
+ /// Assume only that dynamically-satisfiable validity conditions are met.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const VALIDITY: Self = Self { validity: true, ..Self::NOTHING };
+
+ /// Assume both `self` and `other_assumptions`.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const fn and(self, other_assumptions: Self) -> Self {
+ Self {
+ alignment: self.alignment || other_assumptions.alignment,
+ lifetimes: self.lifetimes || other_assumptions.lifetimes,
+ safety: self.safety || other_assumptions.safety,
+ validity: self.validity || other_assumptions.validity,
+ }
+ }
+
+ /// Assume `self`, excepting `other_assumptions`.
+ #[unstable(feature = "transmutability", issue = "99571")]
+ pub const fn but_not(self, other_assumptions: Self) -> Self {
+ Self {
+ alignment: self.alignment && !other_assumptions.alignment,
+ lifetimes: self.lifetimes && !other_assumptions.lifetimes,
+ safety: self.safety && !other_assumptions.safety,
+ validity: self.validity && !other_assumptions.validity,
+ }
+ }
+}
+
+// FIXME(jswrenn): This const op is not actually usable. Why?
+// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926
+#[unstable(feature = "transmutability", issue = "99571")]
+#[rustc_const_unstable(feature = "transmutability", issue = "99571")]
+impl const core::ops::Add for Assume {
+ type Output = Assume;
+
+ fn add(self, other_assumptions: Assume) -> Assume {
+ self.and(other_assumptions)
+ }
+}
+
+// FIXME(jswrenn): This const op is not actually usable. Why?
+// https://github.com/rust-lang/rust/pull/100726#issuecomment-1219928926
+#[unstable(feature = "transmutability", issue = "99571")]
+#[rustc_const_unstable(feature = "transmutability", issue = "99571")]
+impl const core::ops::Sub for Assume {
+ type Output = Assume;
+
+ fn sub(self, other_assumptions: Assume) -> Assume {
+ self.but_not(other_assumptions)
+ }
}
diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs
index de85fdd6e..d2a21b6b3 100644
--- a/library/core/src/num/bignum.rs
+++ b/library/core/src/num/bignum.rs
@@ -137,7 +137,7 @@ macro_rules! define_bignum {
// Find the most significant non-zero digit.
let msd = digits.iter().rposition(|&x| x != 0);
match msd {
- Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1,
+ Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1,
// There are no non-zero digits, i.e., the number is zero.
_ => 0,
}
diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/dec2flt/decimal.rs
index f8edc3625..2019f71e6 100644
--- a/library/core/src/num/dec2flt/decimal.rs
+++ b/library/core/src/num/dec2flt/decimal.rs
@@ -32,7 +32,7 @@ impl Default for Decimal {
impl Decimal {
/// The maximum number of digits required to unambiguously round a float.
///
- /// For a double-precision IEEE-754 float, this required 767 digits,
+ /// For a double-precision IEEE 754 float, this required 767 digits,
/// so we store the max digits + 1.
///
/// We can exactly represent a float in radix `b` from radix 2 if
diff --git a/library/core/src/num/dec2flt/lemire.rs b/library/core/src/num/dec2flt/lemire.rs
index 75405f471..9f7594460 100644
--- a/library/core/src/num/dec2flt/lemire.rs
+++ b/library/core/src/num/dec2flt/lemire.rs
@@ -6,7 +6,7 @@ use crate::num::dec2flt::table::{
LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE,
};
-/// Compute a float using an extended-precision representation.
+/// Compute w * 10^q using an extended-precision float representation.
///
/// Fast conversion of a the significant digits and decimal exponent
/// a float to an extended representation with a binary float. This
@@ -76,7 +76,7 @@ pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp {
return BiasedFp { f: mantissa, e: power2 };
}
// Need to handle rounding ties. Normally, we need to round up,
- // but if we fall right in between and and we have an even basis, we
+ // but if we fall right in between and we have an even basis, we
// need to round down.
//
// This will only occur if:
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index 1a223016d..768dd8781 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -1,6 +1,7 @@
//! Error types for conversion to integral types.
use crate::convert::Infallible;
+use crate::error::Error;
use crate::fmt;
/// The error type returned when a checked integral type conversion fails.
@@ -144,3 +145,19 @@ impl fmt::Display for ParseIntError {
self.__description().fmt(f)
}
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for ParseIntError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[stable(feature = "try_from", since = "1.34.0")]
+impl Error for TryFromIntError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 6548ad2e5..2c6a0ba64 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -1,4 +1,4 @@
-//! Constants specific to the `f32` single-precision floating point type.
+//! Constants for the `f32` single-precision floating point type.
//!
//! *[See also the `f32` primitive type][f32].*
//!
@@ -394,7 +394,7 @@ impl f32 {
/// Not a Number (NaN).
///
- /// Note that IEEE-745 doesn't define just a single NaN value;
+ /// Note that IEEE 754 doesn't define just a single NaN value;
/// a plethora of bit patterns are considered to be NaN.
/// Furthermore, the standard makes a difference
/// between a "signaling" and a "quiet" NaN,
@@ -632,7 +632,7 @@ impl f32 {
}
/// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
- /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any
+ /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
/// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
@@ -654,7 +654,7 @@ impl f32 {
}
/// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
- /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any
+ /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
/// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
@@ -678,6 +678,106 @@ impl f32 {
unsafe { mem::transmute::<f32, u32>(self) & 0x8000_0000 != 0 }
}
+ /// Returns the least number greater than `self`.
+ ///
+ /// Let `TINY` be the smallest representable positive `f32`. Then,
+ /// - if `self.is_nan()`, this returns `self`;
+ /// - if `self` is [`NEG_INFINITY`], this returns [`MIN`];
+ /// - if `self` is `-TINY`, this returns -0.0;
+ /// - if `self` is -0.0 or +0.0, this returns `TINY`;
+ /// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`];
+ /// - otherwise the unique least value greater than `self` is returned.
+ ///
+ /// The identity `x.next_up() == -(-x).next_down()` holds for all non-NaN `x`. When `x`
+ /// is finite `x == x.next_up().next_down()` also holds.
+ ///
+ /// ```rust
+ /// #![feature(float_next_up_down)]
+ /// // f32::EPSILON is the difference between 1.0 and the next number up.
+ /// assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON);
+ /// // But not for most numbers.
+ /// assert!(0.1f32.next_up() < 0.1 + f32::EPSILON);
+ /// assert_eq!(16777216f32.next_up(), 16777218.0);
+ /// ```
+ ///
+ /// [`NEG_INFINITY`]: Self::NEG_INFINITY
+ /// [`INFINITY`]: Self::INFINITY
+ /// [`MIN`]: Self::MIN
+ /// [`MAX`]: Self::MAX
+ #[unstable(feature = "float_next_up_down", issue = "91399")]
+ #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
+ pub const fn next_up(self) -> Self {
+ // We must use strictly integer arithmetic to prevent denormals from
+ // flushing to zero after an arithmetic operation on some platforms.
+ const TINY_BITS: u32 = 0x1; // Smallest positive f32.
+ const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff;
+
+ let bits = self.to_bits();
+ if self.is_nan() || bits == Self::INFINITY.to_bits() {
+ return self;
+ }
+
+ let abs = bits & CLEAR_SIGN_MASK;
+ let next_bits = if abs == 0 {
+ TINY_BITS
+ } else if bits == abs {
+ bits + 1
+ } else {
+ bits - 1
+ };
+ Self::from_bits(next_bits)
+ }
+
+ /// Returns the greatest number less than `self`.
+ ///
+ /// Let `TINY` be the smallest representable positive `f32`. Then,
+ /// - if `self.is_nan()`, this returns `self`;
+ /// - if `self` is [`INFINITY`], this returns [`MAX`];
+ /// - if `self` is `TINY`, this returns 0.0;
+ /// - if `self` is -0.0 or +0.0, this returns `-TINY`;
+ /// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`];
+ /// - otherwise the unique greatest value less than `self` is returned.
+ ///
+ /// The identity `x.next_down() == -(-x).next_up()` holds for all non-NaN `x`. When `x`
+ /// is finite `x == x.next_down().next_up()` also holds.
+ ///
+ /// ```rust
+ /// #![feature(float_next_up_down)]
+ /// let x = 1.0f32;
+ /// // Clamp value into range [0, 1).
+ /// let clamped = x.clamp(0.0, 1.0f32.next_down());
+ /// assert!(clamped < 1.0);
+ /// assert_eq!(clamped.next_up(), 1.0);
+ /// ```
+ ///
+ /// [`NEG_INFINITY`]: Self::NEG_INFINITY
+ /// [`INFINITY`]: Self::INFINITY
+ /// [`MIN`]: Self::MIN
+ /// [`MAX`]: Self::MAX
+ #[unstable(feature = "float_next_up_down", issue = "91399")]
+ #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
+ pub const fn next_down(self) -> Self {
+ // We must use strictly integer arithmetic to prevent denormals from
+ // flushing to zero after an arithmetic operation on some platforms.
+ const NEG_TINY_BITS: u32 = 0x8000_0001; // Smallest (in magnitude) negative f32.
+ const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff;
+
+ let bits = self.to_bits();
+ if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() {
+ return self;
+ }
+
+ let abs = bits & CLEAR_SIGN_MASK;
+ let next_bits = if abs == 0 {
+ NEG_TINY_BITS
+ } else if bits == abs {
+ bits - 1
+ } else {
+ bits + 1
+ };
+ Self::from_bits(next_bits)
+ }
+
/// Takes the reciprocal (inverse) of a number, `1/x`.
///
/// ```
@@ -733,7 +833,7 @@ impl f32 {
/// Returns the maximum of the two numbers, ignoring NaN.
///
/// If one of the arguments is NaN, then the other argument is returned.
- /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs;
+ /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
/// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
/// This also matches the behavior of libm’s fmax.
///
@@ -753,7 +853,7 @@ impl f32 {
/// Returns the minimum of the two numbers, ignoring NaN.
///
/// If one of the arguments is NaN, then the other argument is returned.
- /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs;
+ /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
/// this function handles all NaNs the same way and avoids minNum's problems with associativity.
/// This also matches the behavior of libm’s fmin.
///
@@ -933,10 +1033,14 @@ impl f32 {
}
}
}
- // SAFETY: `u32` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- let rt_f32_to_u32 = |rt| unsafe { mem::transmute::<f32, u32>(rt) };
+
+ #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+ fn rt_f32_to_u32(x: f32) -> u32 {
+ // SAFETY: `u32` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ unsafe { mem::transmute(x) }
+ }
// SAFETY: We use internal implementations that either always work or fail at compile time.
unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
}
@@ -947,9 +1051,9 @@ impl f32 {
/// It turns out this is incredibly portable, for two reasons:
///
/// * Floats and Ints have the same endianness on all supported platforms.
- /// * IEEE-754 very precisely specifies the bit layout of floats.
+ /// * IEEE 754 very precisely specifies the bit layout of floats.
///
- /// However there is one caveat: prior to the 2008 version of IEEE-754, how
+ /// However there is one caveat: prior to the 2008 version of IEEE 754, how
/// to interpret the NaN signaling bit wasn't actually specified. Most platforms
/// (notably x86 and ARM) picked the interpretation that was ultimately
/// standardized in 2008, but some didn't (notably MIPS). As a result, all
@@ -1021,10 +1125,14 @@ impl f32 {
}
}
}
- // SAFETY: `u32` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- let rt_u32_to_f32 = |rt| unsafe { mem::transmute::<u32, f32>(rt) };
+
+ #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+ fn rt_u32_to_f32(x: u32) -> f32 {
+ // SAFETY: `u32` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ unsafe { mem::transmute(x) }
+ }
// SAFETY: We use internal implementations that either always work or fail at compile time.
unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) }
}
@@ -1282,15 +1390,14 @@ impl f32 {
#[must_use = "method returns a new number and does not mutate the original value"]
#[stable(feature = "clamp", since = "1.50.0")]
#[inline]
- pub fn clamp(self, min: f32, max: f32) -> f32 {
+ pub fn clamp(mut self, min: f32, max: f32) -> f32 {
assert!(min <= max);
- let mut x = self;
- if x < min {
- x = min;
+ if self < min {
+ self = min;
}
- if x > max {
- x = max;
+ if self > max {
+ self = max;
}
- x
+ self
}
}
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 75c92c2f8..fd3c18ce2 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -1,4 +1,4 @@
-//! Constants specific to the `f64` double-precision floating point type.
+//! Constants for the `f64` double-precision floating point type.
//!
//! *[See also the `f64` primitive type][f64].*
//!
@@ -393,7 +393,7 @@ impl f64 {
/// Not a Number (NaN).
///
- /// Note that IEEE-745 doesn't define just a single NaN value;
+ /// Note that IEEE 754 doesn't define just a single NaN value;
/// a plethora of bit patterns are considered to be NaN.
/// Furthermore, the standard makes a difference
/// between a "signaling" and a "quiet" NaN,
@@ -624,7 +624,7 @@ impl f64 {
}
/// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
- /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any
+ /// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
/// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
@@ -655,7 +655,7 @@ impl f64 {
}
/// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
- /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any
+ /// negative sign bit and negative infinity. Note that IEEE 754 doesn't assign any
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
/// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
@@ -688,6 +688,106 @@ impl f64 {
self.is_sign_negative()
}
+ /// Returns the least number greater than `self`.
+ ///
+ /// Let `TINY` be the smallest representable positive `f64`. Then,
+ /// - if `self.is_nan()`, this returns `self`;
+ /// - if `self` is [`NEG_INFINITY`], this returns [`MIN`];
+ /// - if `self` is `-TINY`, this returns -0.0;
+ /// - if `self` is -0.0 or +0.0, this returns `TINY`;
+ /// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`];
+ /// - otherwise the unique least value greater than `self` is returned.
+ ///
+ /// The identity `x.next_up() == -(-x).next_down()` holds for all non-NaN `x`. When `x`
+ /// is finite `x == x.next_up().next_down()` also holds.
+ ///
+ /// ```rust
+ /// #![feature(float_next_up_down)]
+ /// // f64::EPSILON is the difference between 1.0 and the next number up.
+ /// assert_eq!(1.0f64.next_up(), 1.0 + f64::EPSILON);
+ /// // But not for most numbers.
+ /// assert!(0.1f64.next_up() < 0.1 + f64::EPSILON);
+ /// assert_eq!(9007199254740992f64.next_up(), 9007199254740994.0);
+ /// ```
+ ///
+ /// [`NEG_INFINITY`]: Self::NEG_INFINITY
+ /// [`INFINITY`]: Self::INFINITY
+ /// [`MIN`]: Self::MIN
+ /// [`MAX`]: Self::MAX
+ #[unstable(feature = "float_next_up_down", issue = "91399")]
+ #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
+ pub const fn next_up(self) -> Self {
+ // We must use strictly integer arithmetic to prevent denormals from
+ // flushing to zero after an arithmetic operation on some platforms.
+ const TINY_BITS: u64 = 0x1; // Smallest positive f64.
+ const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff;
+
+ let bits = self.to_bits();
+ if self.is_nan() || bits == Self::INFINITY.to_bits() {
+ return self;
+ }
+
+ let abs = bits & CLEAR_SIGN_MASK;
+ let next_bits = if abs == 0 {
+ TINY_BITS
+ } else if bits == abs {
+ bits + 1
+ } else {
+ bits - 1
+ };
+ Self::from_bits(next_bits)
+ }
+
+ /// Returns the greatest number less than `self`.
+ ///
+ /// Let `TINY` be the smallest representable positive `f64`. Then,
+ /// - if `self.is_nan()`, this returns `self`;
+ /// - if `self` is [`INFINITY`], this returns [`MAX`];
+ /// - if `self` is `TINY`, this returns 0.0;
+ /// - if `self` is -0.0 or +0.0, this returns `-TINY`;
+ /// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`];
+ /// - otherwise the unique greatest value less than `self` is returned.
+ ///
+ /// The identity `x.next_down() == -(-x).next_up()` holds for all non-NaN `x`. When `x`
+ /// is finite `x == x.next_down().next_up()` also holds.
+ ///
+ /// ```rust
+ /// #![feature(float_next_up_down)]
+ /// let x = 1.0f64;
+ /// // Clamp value into range [0, 1).
+ /// let clamped = x.clamp(0.0, 1.0f64.next_down());
+ /// assert!(clamped < 1.0);
+ /// assert_eq!(clamped.next_up(), 1.0);
+ /// ```
+ ///
+ /// [`NEG_INFINITY`]: Self::NEG_INFINITY
+ /// [`INFINITY`]: Self::INFINITY
+ /// [`MIN`]: Self::MIN
+ /// [`MAX`]: Self::MAX
+ #[unstable(feature = "float_next_up_down", issue = "91399")]
+ #[rustc_const_unstable(feature = "float_next_up_down", issue = "91399")]
+ pub const fn next_down(self) -> Self {
+ // We must use strictly integer arithmetic to prevent denormals from
+ // flushing to zero after an arithmetic operation on some platforms.
+ const NEG_TINY_BITS: u64 = 0x8000_0000_0000_0001; // Smallest (in magnitude) negative f64.
+ const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff;
+
+ let bits = self.to_bits();
+ if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() {
+ return self;
+ }
+
+ let abs = bits & CLEAR_SIGN_MASK;
+ let next_bits = if abs == 0 {
+ NEG_TINY_BITS
+ } else if bits == abs {
+ bits - 1
+ } else {
+ bits + 1
+ };
+ Self::from_bits(next_bits)
+ }
+
/// Takes the reciprocal (inverse) of a number, `1/x`.
///
/// ```
@@ -744,7 +844,7 @@ impl f64 {
/// Returns the maximum of the two numbers, ignoring NaN.
///
/// If one of the arguments is NaN, then the other argument is returned.
- /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs;
+ /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
/// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
/// This also matches the behavior of libm’s fmax.
///
@@ -764,7 +864,7 @@ impl f64 {
/// Returns the minimum of the two numbers, ignoring NaN.
///
/// If one of the arguments is NaN, then the other argument is returned.
- /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs;
+ /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
/// this function handles all NaNs the same way and avoids minNum's problems with associativity.
/// This also matches the behavior of libm’s fmin.
///
@@ -926,10 +1026,14 @@ impl f64 {
}
}
}
- // SAFETY: `u64` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- let rt_f64_to_u64 = |rt| unsafe { mem::transmute::<f64, u64>(rt) };
+
+ #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+ fn rt_f64_to_u64(rt: f64) -> u64 {
+ // SAFETY: `u64` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ unsafe { mem::transmute::<f64, u64>(rt) }
+ }
// SAFETY: We use internal implementations that either always work or fail at compile time.
unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
}
@@ -940,9 +1044,9 @@ impl f64 {
/// It turns out this is incredibly portable, for two reasons:
///
/// * Floats and Ints have the same endianness on all supported platforms.
- /// * IEEE-754 very precisely specifies the bit layout of floats.
+ /// * IEEE 754 very precisely specifies the bit layout of floats.
///
- /// However there is one caveat: prior to the 2008 version of IEEE-754, how
+ /// However there is one caveat: prior to the 2008 version of IEEE 754, how
/// to interpret the NaN signaling bit wasn't actually specified. Most platforms
/// (notably x86 and ARM) picked the interpretation that was ultimately
/// standardized in 2008, but some didn't (notably MIPS). As a result, all
@@ -1019,10 +1123,14 @@ impl f64 {
}
}
}
- // SAFETY: `u64` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- let rt_u64_to_f64 = |rt| unsafe { mem::transmute::<u64, f64>(rt) };
+
+ #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
+ fn rt_u64_to_f64(rt: u64) -> f64 {
+ // SAFETY: `u64` is a plain old datatype so we can always... uh...
+ // ...look, just pretend you forgot what you just read.
+ // Stability concerns.
+ unsafe { mem::transmute::<u64, f64>(rt) }
+ }
// SAFETY: We use internal implementations that either always work or fail at compile time.
unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) }
}
@@ -1280,15 +1388,14 @@ impl f64 {
#[must_use = "method returns a new number and does not mutate the original value"]
#[stable(feature = "clamp", since = "1.50.0")]
#[inline]
- pub fn clamp(self, min: f64, max: f64) -> f64 {
+ pub fn clamp(mut self, min: f64, max: f64) -> f64 {
assert!(min <= max);
- let mut x = self;
- if x < min {
- x = min;
+ if self < min {
+ self = min;
}
- if x > max {
- x = max;
+ if self > max {
+ self = max;
}
- x
+ self
}
}
diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs
index a4cb51c62..ed3e0edaf 100644
--- a/library/core/src/num/flt2dec/strategy/grisu.rs
+++ b/library/core/src/num/flt2dec/strategy/grisu.rs
@@ -253,7 +253,6 @@ pub fn format_shortest_opt<'a>(
let delta1frac = delta1 & ((1 << e) - 1);
// render integral parts, while checking for the accuracy at each step.
- let mut kappa = max_kappa as i16;
let mut ten_kappa = max_ten_kappa; // 10^kappa
let mut remainder = plus1int; // digits yet to be rendered
loop {
@@ -290,12 +289,10 @@ pub fn format_shortest_opt<'a>(
// the exact number of digits is `max_kappa + 1` as `plus1 < 10^(max_kappa+1)`.
if i > max_kappa as usize {
debug_assert_eq!(ten_kappa, 1);
- debug_assert_eq!(kappa, 0);
break;
}
// restore invariants
- kappa -= 1;
ten_kappa /= 10;
remainder = r;
}
@@ -338,7 +335,6 @@ pub fn format_shortest_opt<'a>(
}
// restore invariants
- kappa -= 1;
remainder = r;
}
diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs
index cc26c04a5..80472528f 100644
--- a/library/core/src/num/int_log10.rs
+++ b/library/core/src/num/int_log10.rs
@@ -1,5 +1,5 @@
/// These functions compute the integer logarithm of their type, assuming
-/// that someone has already checked that the the value is strictly positive.
+/// that someone has already checked that the value is strictly positive.
// 0 < val <= u8::MAX
#[inline]
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index a66de19ba..914dca61b 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -464,12 +464,11 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -533,12 +532,11 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -654,7 +652,6 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));")]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);")]
@@ -706,7 +703,6 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);")]
/// ```
@@ -822,7 +818,6 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- ///
#[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);")]
/// ```
@@ -874,7 +869,7 @@ macro_rules! int_impl {
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- Some(try_opt!(acc.checked_mul(base)))
+ acc.checked_mul(base)
}
/// Saturating integer addition. Computes `self + rhs`, saturating at the numeric
@@ -907,12 +902,11 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -954,12 +948,11 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -1030,7 +1023,6 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- ///
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);")]
@@ -1089,7 +1081,6 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- ///
#[doc = concat!("assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);")]
@@ -1135,12 +1126,11 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@@ -1176,12 +1166,11 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")]
#[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
@@ -1504,7 +1493,6 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), "::MIN, true));")]
/// ```
@@ -1518,6 +1506,51 @@ macro_rules! int_impl {
(a as Self, b)
}
+ /// Calculates `self + rhs + carry` without the ability to overflow.
+ ///
+ /// Performs "signed ternary addition" which takes in an extra bit to add, and may return an
+ /// additional bit of overflow. This signed function is used only on the highest-ordered data,
+ /// for which the signed overflow result indicates whether the big integer overflowed or not.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, true));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (", stringify!($SelfT), "::MIN, true));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, true));")]
+ #[doc = concat!("assert_eq!(",
+ stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ",
+ "(-1, true));"
+ )]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.carrying_add(-1, true), (", stringify!($SelfT), "::MIN, false));")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".carrying_add(", stringify!($SelfT), "::MAX, true), (", stringify!($SelfT), "::MIN, true));")]
+ /// ```
+ ///
+ /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add):
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")]
+ /// ```
+ #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+ #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
+ // note: longer-term this should be done via an intrinsic.
+ // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946).
+ let (a, b) = self.overflowing_add(rhs);
+ let (c, d) = a.overflowing_add(carry as $SelfT);
+ (c, b != d)
+ }
+
/// Calculates `self` + `rhs` with an unsigned `rhs`
///
/// Returns a tuple of the addition along with a boolean indicating
@@ -1529,13 +1562,12 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_unsigned(2), (3, false));")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_unsigned(3), (", stringify!($SelfT), "::MIN, true));")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -1555,7 +1587,6 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));")]
/// ```
@@ -1569,6 +1600,39 @@ macro_rules! int_impl {
(a as Self, b)
}
+ /// Calculates `self - rhs - borrow` without the ability to overflow.
+ ///
+ /// Performs "signed ternary subtraction" which takes in an extra bit to subtract, and may return an
+ /// additional bit of overflow. This signed function is used only on the highest-ordered data,
+ /// for which the signed overflow result indicates whether the big integer overflowed or not.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (-1, false));")]
+ #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (-2, false));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, false), (", stringify!($SelfT), "::MIN, true));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, true), (", stringify!($SelfT), "::MAX, false));")]
+ /// ```
+ #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+ #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
+ // note: longer-term this should be done via an intrinsic.
+ // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946).
+ let (a, b) = self.overflowing_sub(rhs);
+ let (c, d) = a.overflowing_sub(borrow as $SelfT);
+ (c, b != d)
+ }
+
/// Calculates `self` - `rhs` with an unsigned `rhs`
///
/// Returns a tuple of the subtraction along with a boolean indicating
@@ -1580,13 +1644,12 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_unsigned(2), (-1, false));")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).overflowing_sub_unsigned(3), (", stringify!($SelfT), "::MAX, true));")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -1633,7 +1696,6 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), "::MIN, true));")]
/// ```
@@ -1696,7 +1758,6 @@ macro_rules! int_impl {
/// Basic usage:
///
/// ```
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));")]
/// ```
@@ -2204,105 +2265,70 @@ macro_rules! int_impl {
/// rounded down.
///
/// This method might not be optimized owing to implementation details;
- /// `log2` can produce results more efficiently for base 2, and `log10`
+ /// `ilog2` can produce results more efficiently for base 2, and `ilog10`
/// can produce results more efficiently for base 10.
///
/// # Panics
///
- /// When the number is negative, zero, or if the base is not at least 2; it
- /// panics in debug mode and the return value is 0 in release
- /// mode.
+ /// This function will panic if `self` is less than or equal to zero,
+ /// or if `base` is less then 2.
///
/// # Examples
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[track_caller]
- #[rustc_inherit_overflow_checks]
- #[allow(arithmetic_overflow)]
- pub const fn log(self, base: Self) -> u32 {
- match self.checked_log(base) {
- Some(n) => n,
- None => {
- // In debug builds, trigger a panic on None.
- // This should optimize completely out in release builds.
- let _ = Self::MAX + 1;
-
- 0
- },
- }
+ pub const fn ilog(self, base: Self) -> u32 {
+ assert!(base >= 2, "base of integer logarithm must be at least 2");
+ self.checked_ilog(base).expect("argument of integer logarithm must be positive")
}
/// Returns the base 2 logarithm of the number, rounded down.
///
/// # Panics
///
- /// When the number is negative or zero it panics in debug mode and the return value
- /// is 0 in release mode.
+ /// This function will panic if `self` is less than or equal to zero.
///
/// # Examples
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[track_caller]
- #[rustc_inherit_overflow_checks]
- #[allow(arithmetic_overflow)]
- pub const fn log2(self) -> u32 {
- match self.checked_log2() {
- Some(n) => n,
- None => {
- // In debug builds, trigger a panic on None.
- // This should optimize completely out in release builds.
- let _ = Self::MAX + 1;
-
- 0
- },
- }
+ pub const fn ilog2(self) -> u32 {
+ self.checked_ilog2().expect("argument of integer logarithm must be positive")
}
/// Returns the base 10 logarithm of the number, rounded down.
///
/// # Panics
///
- /// When the number is negative or zero it panics in debug mode and the return value
- /// is 0 in release mode.
+ /// This function will panic if `self` is less than or equal to zero.
///
/// # Example
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[track_caller]
- #[rustc_inherit_overflow_checks]
- #[allow(arithmetic_overflow)]
- pub const fn log10(self) -> u32 {
- match self.checked_log10() {
- Some(n) => n,
- None => {
- // In debug builds, trigger a panic on None.
- // This should optimize completely out in release builds.
- let _ = Self::MAX + 1;
-
- 0
- },
- }
+ pub const fn ilog10(self) -> u32 {
+ self.checked_ilog10().expect("argument of integer logarithm must be positive")
}
/// Returns the logarithm of the number with respect to an arbitrary base,
@@ -2311,20 +2337,20 @@ macro_rules! int_impl {
/// Returns `None` if the number is negative or zero, or if the base is not at least 2.
///
/// This method might not be optimized owing to implementation details;
- /// `checked_log2` can produce results more efficiently for base 2, and
- /// `checked_log10` can produce results more efficiently for base 10.
+ /// `checked_ilog2` can produce results more efficiently for base 2, and
+ /// `checked_ilog10` can produce results more efficiently for base 10.
///
/// # Examples
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log(self, base: Self) -> Option<u32> {
+ pub const fn checked_ilog(self, base: Self) -> Option<u32> {
if self <= 0 || base <= 1 {
None
} else {
@@ -2333,7 +2359,7 @@ macro_rules! int_impl {
// Optimization for 128 bit wide integers.
if Self::BITS == 128 {
- let b = Self::log2(self) / (Self::log2(base) + 1);
+ let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
n += b;
r /= base.pow(b as u32);
}
@@ -2354,13 +2380,13 @@ macro_rules! int_impl {
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log2(self) -> Option<u32> {
+ pub const fn checked_ilog2(self) -> Option<u32> {
if self <= 0 {
None
} else {
@@ -2378,13 +2404,13 @@ macro_rules! int_impl {
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log10(self) -> Option<u32> {
+ pub const fn checked_ilog10(self) -> Option<u32> {
if self > 0 {
Some(int_log10::$ActualT(self as $ActualT))
} else {
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index f481399fd..311c5fa5b 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -3,6 +3,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::ascii;
+use crate::error::Error;
use crate::intrinsics;
use crate::mem;
use crate::ops::{Add, Mul, Sub};
@@ -57,6 +58,15 @@ pub use wrapping::Wrapping;
#[cfg(not(no_fp_fmt_parse))]
pub use dec2flt::ParseFloatError;
+#[cfg(not(no_fp_fmt_parse))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for ParseFloatError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
pub use error::ParseIntError;
@@ -101,6 +111,9 @@ macro_rules! widening_impl {
/// This returns the low-order (wrapping) bits and the high-order (overflow) bits
/// of the result as two separate values, in that order.
///
+ /// If you also need to add a carry to the wide result, then you want
+ /// [`Self::carrying_mul`] instead.
+ ///
/// # Examples
///
/// Basic usage:
@@ -136,6 +149,8 @@ macro_rules! widening_impl {
/// additional amount of overflow. This allows for chaining together multiple
/// multiplications to create "big integers" which represent larger values.
///
+ /// If you don't need the `carry`, then you can use [`Self::widening_mul`] instead.
+ ///
/// # Examples
///
/// Basic usage:
@@ -155,6 +170,31 @@ macro_rules! widening_impl {
)]
/// ```
///
+ /// This is the core operation needed for scalar multiplication when
+ /// implementing it for wider-than-native types.
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ /// fn scalar_mul_eq(little_endian_digits: &mut Vec<u16>, multiplicand: u16) {
+ /// let mut carry = 0;
+ /// for d in little_endian_digits.iter_mut() {
+ /// (*d, carry) = d.carrying_mul(multiplicand, carry);
+ /// }
+ /// if carry != 0 {
+ /// little_endian_digits.push(carry);
+ /// }
+ /// }
+ ///
+ /// let mut v = vec![10, 20];
+ /// scalar_mul_eq(&mut v, 3);
+ /// assert_eq!(v, [30, 60]);
+ ///
+ /// assert_eq!(0x87654321_u64 * 0xFEED, 0x86D3D159E38D);
+ /// let mut v = vec![0x4321, 0x8765];
+ /// scalar_mul_eq(&mut v, 0xFEED);
+ /// assert_eq!(v, [0xE38D, 0xD159, 0x86D3]);
+ /// ```
+ ///
/// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul),
/// except that it gives the value of the overflow instead of just whether one happened:
///
@@ -582,6 +622,38 @@ impl u8 {
matches!(*self, b'0'..=b'9')
}
+ /// Checks if the value is an ASCII octal digit:
+ /// U+0030 '0' ..= U+0037 '7'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(is_ascii_octdigit)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let a = b'a';
+ /// let zero = b'0';
+ /// let seven = b'7';
+ /// let nine = b'9';
+ /// let percent = b'%';
+ /// let lf = b'\n';
+ ///
+ /// assert!(!uppercase_a.is_ascii_octdigit());
+ /// assert!(!a.is_ascii_octdigit());
+ /// assert!(zero.is_ascii_octdigit());
+ /// assert!(seven.is_ascii_octdigit());
+ /// assert!(!nine.is_ascii_octdigit());
+ /// assert!(!percent.is_ascii_octdigit());
+ /// assert!(!lf.is_ascii_octdigit());
+ /// ```
+ #[must_use]
+ #[unstable(feature = "is_ascii_octdigit", issue = "101288")]
+ #[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")]
+ #[inline]
+ pub const fn is_ascii_octdigit(&self) -> bool {
+ matches!(*self, b'0'..=b'7')
+ }
+
/// Checks if the value is an ASCII hexadecimal digit:
///
/// - U+0030 '0' ..= U+0039 '9', or
@@ -623,7 +695,7 @@ impl u8 {
///
/// - U+0021 ..= U+002F `! " # $ % & ' ( ) * + , - . /`, or
/// - U+003A ..= U+0040 `: ; < = > ? @`, or
- /// - U+005B ..= U+0060 ``[ \ ] ^ _ ` ``, or
+ /// - U+005B ..= U+0060 `` [ \ ] ^ _ ` ``, or
/// - U+007B ..= U+007E `{ | } ~`
///
/// # Examples
@@ -936,8 +1008,8 @@ impl usize {
/// assert_eq!(num.classify(), FpCategory::Normal);
/// assert_eq!(inf.classify(), FpCategory::Infinite);
/// assert_eq!(zero.classify(), FpCategory::Zero);
-/// assert_eq!(nan.classify(), FpCategory::Nan);
/// assert_eq!(sub.classify(), FpCategory::Subnormal);
+/// assert_eq!(nan.classify(), FpCategory::Nan);
/// ```
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 4de0a0cf5..6b6f3417f 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -56,7 +56,10 @@ macro_rules! nonzero_integers {
pub const unsafe fn new_unchecked(n: $Int) -> Self {
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
- core::intrinsics::assert_unsafe_precondition!(n != 0);
+ core::intrinsics::assert_unsafe_precondition!(
+ concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument"),
+ (n: $Int) => n != 0
+ );
Self(n)
}
}
@@ -309,8 +312,8 @@ macro_rules! nonzero_unsigned_operations {
( $( $Ty: ident($Int: ident); )+ ) => {
$(
impl $Ty {
- /// Add an unsigned integer to a non-zero value.
- /// Check for overflow and return [`None`] on overflow
+ /// Adds an unsigned integer to a non-zero value.
+ /// Checks for overflow and returns [`None`] on overflow.
/// As a consequence, the result cannot wrap to zero.
///
///
@@ -346,7 +349,7 @@ macro_rules! nonzero_unsigned_operations {
}
}
- /// Add an unsigned integer to a non-zero value.
+ /// Adds an unsigned integer to a non-zero value.
#[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
///
/// # Examples
@@ -377,7 +380,7 @@ macro_rules! nonzero_unsigned_operations {
unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) }
}
- /// Add an unsigned integer to a non-zero value,
+ /// Adds an unsigned integer to a non-zero value,
/// assuming overflow cannot occur.
/// Overflow is unchecked, and it is undefined behaviour to overflow
/// *even if the result would wrap to a non-zero value*.
@@ -409,7 +412,7 @@ macro_rules! nonzero_unsigned_operations {
}
/// Returns the smallest power of two greater than or equal to n.
- /// Check for overflow and return [`None`]
+ /// Checks for overflow and returns [`None`]
/// if the next power of two is greater than the type’s maximum value.
/// As a consequence, the result cannot wrap to zero.
///
@@ -450,7 +453,7 @@ macro_rules! nonzero_unsigned_operations {
/// Returns the base 2 logarithm of the number, rounded down.
///
/// This is the same operation as
- #[doc = concat!("[`", stringify!($Int), "::log2`],")]
+ #[doc = concat!("[`", stringify!($Int), "::ilog2`],")]
/// except that it has no failure cases to worry about
/// since this value can never be zero.
///
@@ -460,22 +463,22 @@ macro_rules! nonzero_unsigned_operations {
/// #![feature(int_log)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")]
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")]
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn log2(self) -> u32 {
+ pub const fn ilog2(self) -> u32 {
Self::BITS - 1 - self.leading_zeros()
}
/// Returns the base 10 logarithm of the number, rounded down.
///
/// This is the same operation as
- #[doc = concat!("[`", stringify!($Int), "::log10`],")]
+ #[doc = concat!("[`", stringify!($Int), "::ilog10`],")]
/// except that it has no failure cases to worry about
/// since this value can never be zero.
///
@@ -485,15 +488,15 @@ macro_rules! nonzero_unsigned_operations {
/// #![feature(int_log)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")]
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")]
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn log10(self) -> u32 {
+ pub const fn ilog10(self) -> u32 {
super::int_log10::$Int(self.0)
}
}
@@ -545,7 +548,7 @@ macro_rules! nonzero_signed_operations {
}
/// Checked absolute value.
- /// Check for overflow and returns [`None`] if
+ /// Checks for overflow and returns [`None`] if
#[doc = concat!("`self == ", stringify!($Int), "::MIN`.")]
/// The result cannot be zero.
///
@@ -721,6 +724,160 @@ macro_rules! nonzero_signed_operations {
// SAFETY: absolute value of nonzero cannot yield zero values.
unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) }
}
+
+ /// Returns `true` if `self` is negative and `false` if the
+ /// number is positive.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_negation_ops)]
+ ///
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+ #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+ ///
+ /// assert!(neg_five.is_negative());
+ /// assert!(!pos_five.is_negative());
+ /// # Some(())
+ /// # }
+ /// ```
+ #[must_use]
+ #[inline]
+ #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ pub const fn is_negative(self) -> bool {
+ self.get().is_negative()
+ }
+
+ /// Checked negation. Computes `-self`, returning `None` if `self == i32::MIN`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_negation_ops)]
+ ///
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+ #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+ #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN)?;")]
+ ///
+ /// assert_eq!(pos_five.checked_neg(), Some(neg_five));
+ /// assert_eq!(min.checked_neg(), None);
+ /// # Some(())
+ /// # }
+ /// ```
+ #[inline]
+ #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ pub const fn checked_neg(self) -> Option<$Ty> {
+ if let Some(result) = self.get().checked_neg() {
+ // SAFETY: negation of nonzero cannot yield zero values.
+ return Some(unsafe { $Ty::new_unchecked(result) });
+ }
+ None
+ }
+
+ /// Negates self, overflowing if this is equal to the minimum value.
+ ///
+ #[doc = concat!("See [`", stringify!($Int), "::overflowing_neg`]")]
+ /// for documentation on overflow behaviour.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_negation_ops)]
+ ///
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+ #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+ #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN)?;")]
+ ///
+ /// assert_eq!(pos_five.overflowing_neg(), (neg_five, false));
+ /// assert_eq!(min.overflowing_neg(), (min, true));
+ /// # Some(())
+ /// # }
+ /// ```
+ #[inline]
+ #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ pub const fn overflowing_neg(self) -> ($Ty, bool) {
+ let (result, overflow) = self.get().overflowing_neg();
+ // SAFETY: negation of nonzero cannot yield zero values.
+ ((unsafe { $Ty::new_unchecked(result) }), overflow)
+ }
+
+ /// Saturating negation. Computes `-self`, returning `MAX` if
+ /// `self == i32::MIN` instead of overflowing.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_negation_ops)]
+ ///
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+ #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+ #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN)?;")]
+ #[doc = concat!("let min_plus_one = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN + 1)?;")]
+ #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX)?;")]
+ ///
+ /// assert_eq!(pos_five.saturating_neg(), neg_five);
+ /// assert_eq!(min.saturating_neg(), max);
+ /// assert_eq!(max.saturating_neg(), min_plus_one);
+ /// # Some(())
+ /// # }
+ /// ```
+ #[inline]
+ #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ pub const fn saturating_neg(self) -> $Ty {
+ if let Some(result) = self.checked_neg() {
+ return result;
+ }
+ $Ty::MAX
+ }
+
+ /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary
+ /// of the type.
+ ///
+ #[doc = concat!("See [`", stringify!($Int), "::wrapping_neg`]")]
+ /// for documentation on overflow behaviour.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_negation_ops)]
+ ///
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
+ #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+ #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN)?;")]
+ ///
+ /// assert_eq!(pos_five.wrapping_neg(), neg_five);
+ /// assert_eq!(min.wrapping_neg(), min);
+ /// # Some(())
+ /// # }
+ /// ```
+ #[inline]
+ #[unstable(feature = "nonzero_negation_ops", issue = "102443")]
+ pub const fn wrapping_neg(self) -> $Ty {
+ let result = self.get().wrapping_neg();
+ // SAFETY: negation of nonzero cannot yield zero values.
+ unsafe { $Ty::new_unchecked(result) }
+ }
}
)+
}
@@ -740,8 +897,8 @@ macro_rules! nonzero_unsigned_signed_operations {
( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => {
$(
impl $Ty {
- /// Multiply two non-zero integers together.
- /// Check for overflow and return [`None`] on overflow.
+ /// Multiplies two non-zero integers together.
+ /// Checks for overflow and returns [`None`] on overflow.
/// As a consequence, the result cannot wrap to zero.
///
/// # Examples
@@ -777,7 +934,7 @@ macro_rules! nonzero_unsigned_signed_operations {
}
}
- /// Multiply two non-zero integers together.
+ /// Multiplies two non-zero integers together.
#[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
///
/// # Examples
@@ -809,7 +966,7 @@ macro_rules! nonzero_unsigned_signed_operations {
unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) }
}
- /// Multiply two non-zero integers together,
+ /// Multiplies two non-zero integers together,
/// assuming overflow cannot occur.
/// Overflow is unchecked, and it is undefined behaviour to overflow
/// *even if the result would wrap to a non-zero value*.
@@ -849,8 +1006,8 @@ macro_rules! nonzero_unsigned_signed_operations {
unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) }
}
- /// Raise non-zero value to an integer power.
- /// Check for overflow and return [`None`] on overflow.
+ /// Raises non-zero value to an integer power.
+ /// Checks for overflow and returns [`None`] on overflow.
/// As a consequence, the result cannot wrap to zero.
///
/// # Examples
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 733655442..335cc5124 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -474,13 +474,12 @@ macro_rules! uint_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_signed(3), None);")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -688,104 +687,69 @@ macro_rules! uint_impl {
/// rounded down.
///
/// This method might not be optimized owing to implementation details;
- /// `log2` can produce results more efficiently for base 2, and `log10`
+ /// `ilog2` can produce results more efficiently for base 2, and `ilog10`
/// can produce results more efficiently for base 10.
///
/// # Panics
///
- /// When the number is zero, or if the base is not at least 2;
- /// it panics in debug mode and the return value is 0 in release mode.
+ /// This function will panic if `self` is zero, or if `base` is less then 2.
///
/// # Examples
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[track_caller]
- #[rustc_inherit_overflow_checks]
- #[allow(arithmetic_overflow)]
- pub const fn log(self, base: Self) -> u32 {
- match self.checked_log(base) {
- Some(n) => n,
- None => {
- // In debug builds, trigger a panic on None.
- // This should optimize completely out in release builds.
- let _ = Self::MAX + 1;
-
- 0
- },
- }
+ pub const fn ilog(self, base: Self) -> u32 {
+ assert!(base >= 2, "base of integer logarithm must be at least 2");
+ self.checked_ilog(base).expect("argument of integer logarithm must be positive")
}
/// Returns the base 2 logarithm of the number, rounded down.
///
/// # Panics
///
- /// When the number is zero it panics in debug mode and
- /// the return value is 0 in release mode.
+ /// This function will panic if `self` is zero.
///
/// # Examples
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[track_caller]
- #[rustc_inherit_overflow_checks]
- #[allow(arithmetic_overflow)]
- pub const fn log2(self) -> u32 {
- match self.checked_log2() {
- Some(n) => n,
- None => {
- // In debug builds, trigger a panic on None.
- // This should optimize completely out in release builds.
- let _ = Self::MAX + 1;
-
- 0
- },
- }
+ pub const fn ilog2(self) -> u32 {
+ self.checked_ilog2().expect("argument of integer logarithm must be positive")
}
/// Returns the base 10 logarithm of the number, rounded down.
///
/// # Panics
///
- /// When the number is zero it panics in debug mode and the
- /// return value is 0 in release mode.
+ /// This function will panic if `self` is zero.
///
/// # Example
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
#[track_caller]
- #[rustc_inherit_overflow_checks]
- #[allow(arithmetic_overflow)]
- pub const fn log10(self) -> u32 {
- match self.checked_log10() {
- Some(n) => n,
- None => {
- // In debug builds, trigger a panic on None.
- // This should optimize completely out in release builds.
- let _ = Self::MAX + 1;
-
- 0
- },
- }
+ pub const fn ilog10(self) -> u32 {
+ self.checked_ilog10().expect("argument of integer logarithm must be positive")
}
/// Returns the logarithm of the number with respect to an arbitrary base,
@@ -794,20 +758,20 @@ macro_rules! uint_impl {
/// Returns `None` if the number is zero, or if the base is not at least 2.
///
/// This method might not be optimized owing to implementation details;
- /// `checked_log2` can produce results more efficiently for base 2, and
- /// `checked_log10` can produce results more efficiently for base 10.
+ /// `checked_ilog2` can produce results more efficiently for base 2, and
+ /// `checked_ilog10` can produce results more efficiently for base 10.
///
/// # Examples
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log(self, base: Self) -> Option<u32> {
+ pub const fn checked_ilog(self, base: Self) -> Option<u32> {
if self <= 0 || base <= 1 {
None
} else {
@@ -816,7 +780,7 @@ macro_rules! uint_impl {
// Optimization for 128 bit wide integers.
if Self::BITS == 128 {
- let b = Self::log2(self) / (Self::log2(base) + 1);
+ let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
n += b;
r /= base.pow(b as u32);
}
@@ -837,15 +801,15 @@ macro_rules! uint_impl {
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log2(self) -> Option<u32> {
+ pub const fn checked_ilog2(self) -> Option<u32> {
if let Some(x) = <$NonZeroT>::new(self) {
- Some(x.log2())
+ Some(x.ilog2())
} else {
None
}
@@ -859,15 +823,15 @@ macro_rules! uint_impl {
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log10(self) -> Option<u32> {
+ pub const fn checked_ilog10(self) -> Option<u32> {
if let Some(x) = <$NonZeroT>::new(self) {
- Some(x.log10())
+ Some(x.ilog10())
} else {
None
}
@@ -1026,7 +990,7 @@ macro_rules! uint_impl {
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- Some(try_opt!(acc.checked_mul(base)))
+ acc.checked_mul(base)
}
/// Saturating integer addition. Computes `self + rhs`, saturating at
@@ -1057,13 +1021,12 @@ macro_rules! uint_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(2), 3);")]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_add_signed(4), ", stringify!($SelfT), "::MAX);")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -1198,13 +1161,12 @@ macro_rules! uint_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(2), 3);")]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_add_signed(4), 1);")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -1494,7 +1456,6 @@ macro_rules! uint_impl {
/// Basic usage
///
/// ```
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));")]
/// ```
@@ -1508,37 +1469,42 @@ macro_rules! uint_impl {
(a as Self, b)
}
- /// Calculates `self + rhs + carry` without the ability to overflow.
+ /// Calculates `self` + `rhs` + `carry` and returns a tuple containing
+ /// the sum and the output carry.
///
- /// Performs "ternary addition" which takes in an extra bit to add, and may return an
- /// additional bit of overflow. This allows for chaining together multiple additions
- /// to create "big integers" which represent larger values.
+ /// Performs "ternary addition" of two integer operands and a carry-in
+ /// bit, and returns an output integer and a carry-out bit. This allows
+ /// chaining together multiple additions to create a wider addition, and
+ /// can be useful for bignum addition.
///
#[doc = concat!("This can be thought of as a ", stringify!($BITS), "-bit \"full adder\", in the electronics sense.")]
///
- /// # Examples
+ /// If the input carry is false, this method is equivalent to
+ /// [`overflowing_add`](Self::overflowing_add), and the output carry is
+ /// equal to the overflow flag. Note that although carry and overflow
+ /// flags are similar for unsigned integers, they are different for
+ /// signed integers.
///
- /// Basic usage
+ /// # Examples
///
/// ```
/// #![feature(bigint_helper_methods)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
- #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (0, true));")]
- #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (0, true));")]
- #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (1, true));")]
- #[doc = concat!("assert_eq!(",
- stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ",
- "(", stringify!($SelfT), "::MAX, true));"
- )]
- /// ```
///
- /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add):
+ #[doc = concat!("// 3 MAX (a = 3 × 2^", stringify!($BITS), " + 2^", stringify!($BITS), " - 1)")]
+ #[doc = concat!("// + 5 7 (b = 5 × 2^", stringify!($BITS), " + 7)")]
+ /// // ---------
+ #[doc = concat!("// 9 6 (sum = 9 × 2^", stringify!($BITS), " + 6)")]
///
- /// ```
- /// #![feature(bigint_helper_methods)]
- #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")]
- #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")]
+ #[doc = concat!("let (a1, a0): (", stringify!($SelfT), ", ", stringify!($SelfT), ") = (3, ", stringify!($SelfT), "::MAX);")]
+ #[doc = concat!("let (b1, b0): (", stringify!($SelfT), ", ", stringify!($SelfT), ") = (5, 7);")]
+ /// let carry0 = false;
+ ///
+ /// let (sum0, carry1) = a0.carrying_add(b0, carry0);
+ /// assert_eq!(carry1, true);
+ /// let (sum1, carry2) = a1.carrying_add(b1, carry1);
+ /// assert_eq!(carry2, false);
+ ///
+ /// assert_eq!((sum1, sum0), (9, 6));
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
@@ -1564,13 +1530,12 @@ macro_rules! uint_impl {
/// Basic usage:
///
/// ```
- /// # #![feature(mixed_integer_ops)]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(2), (3, false));")]
#[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")]
#[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_signed(4), (1, true));")]
/// ```
- #[unstable(feature = "mixed_integer_ops", issue = "87840")]
- #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+ #[stable(feature = "mixed_integer_ops", since = "1.66.0")]
+ #[rustc_const_stable(feature = "mixed_integer_ops", since = "1.66.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -1590,7 +1555,6 @@ macro_rules! uint_impl {
/// Basic usage
///
/// ```
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")]
#[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));")]
/// ```
@@ -1604,22 +1568,35 @@ macro_rules! uint_impl {
(a as Self, b)
}
- /// Calculates `self - rhs - borrow` without the ability to overflow.
+ /// Calculates `self` &minus; `rhs` &minus; `borrow` and returns a tuple
+ /// containing the difference and the output borrow.
///
- /// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return
- /// an additional bit of overflow. This allows for chaining together multiple subtractions
- /// to create "big integers" which represent larger values.
+ /// Performs "ternary subtraction" by subtracting both an integer
+ /// operand and a borrow-in bit from `self`, and returns an output
+ /// integer and a borrow-out bit. This allows chaining together multiple
+ /// subtractions to create a wider subtraction, and can be useful for
+ /// bignum subtraction.
///
/// # Examples
///
- /// Basic usage
- ///
/// ```
/// #![feature(bigint_helper_methods)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
- #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (", stringify!($SelfT), "::MAX, true));")]
- #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")]
+ ///
+ #[doc = concat!("// 9 6 (a = 9 × 2^", stringify!($BITS), " + 6)")]
+ #[doc = concat!("// - 5 7 (b = 5 × 2^", stringify!($BITS), " + 7)")]
+ /// // ---------
+ #[doc = concat!("// 3 MAX (diff = 3 × 2^", stringify!($BITS), " + 2^", stringify!($BITS), " - 1)")]
+ ///
+ #[doc = concat!("let (a1, a0): (", stringify!($SelfT), ", ", stringify!($SelfT), ") = (9, 6);")]
+ #[doc = concat!("let (b1, b0): (", stringify!($SelfT), ", ", stringify!($SelfT), ") = (5, 7);")]
+ /// let borrow0 = false;
+ ///
+ /// let (diff0, borrow1) = a0.borrowing_sub(b0, borrow0);
+ /// assert_eq!(borrow1, true);
+ /// let (diff1, borrow2) = a1.borrowing_sub(b1, borrow1);
+ /// assert_eq!(borrow2, false);
+ ///
+ #[doc = concat!("assert_eq!((diff1, diff0), (3, ", stringify!($SelfT), "::MAX));")]
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index e367be8c1..75c52d3ec 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -65,38 +65,15 @@
/// ```
#[lang = "add"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(
- bootstrap,
- rustc_on_unimplemented(
- on(
- all(_Self = "{integer}", Rhs = "{float}"),
- message = "cannot add a float to an integer",
- ),
- on(
- all(_Self = "{float}", Rhs = "{integer}"),
- message = "cannot add an integer to a float",
- ),
- message = "cannot add `{Rhs}` to `{Self}`",
- label = "no implementation for `{Self} + {Rhs}`"
- )
-)]
-#[cfg_attr(
- not(bootstrap),
- rustc_on_unimplemented(
- on(
- all(_Self = "{integer}", Rhs = "{float}"),
- message = "cannot add a float to an integer",
- ),
- on(
- all(_Self = "{float}", Rhs = "{integer}"),
- message = "cannot add an integer to a float",
- ),
- message = "cannot add `{Rhs}` to `{Self}`",
- label = "no implementation for `{Self} + {Rhs}`",
- append_const_msg,
- )
+#[rustc_on_unimplemented(
+ on(all(_Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",),
+ on(all(_Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",),
+ message = "cannot add `{Rhs}` to `{Self}`",
+ label = "no implementation for `{Self} + {Rhs}`",
+ append_const_msg
)]
#[doc(alias = "+")]
+#[const_trait]
pub trait Add<Rhs = Self> {
/// The resulting type after applying the `+` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -201,9 +178,11 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
message = "cannot subtract `{Rhs}` from `{Self}`",
- label = "no implementation for `{Self} - {Rhs}`"
+ label = "no implementation for `{Self} - {Rhs}`",
+ append_const_msg
)]
#[doc(alias = "-")]
+#[const_trait]
pub trait Sub<Rhs = Self> {
/// The resulting type after applying the `-` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -333,6 +312,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
label = "no implementation for `{Self} * {Rhs}`"
)]
#[doc(alias = "*")]
+#[const_trait]
pub trait Mul<Rhs = Self> {
/// The resulting type after applying the `*` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -466,6 +446,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
label = "no implementation for `{Self} / {Rhs}`"
)]
#[doc(alias = "/")]
+#[const_trait]
pub trait Div<Rhs = Self> {
/// The resulting type after applying the `/` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -568,6 +549,7 @@ div_impl_float! { f32 f64 }
label = "no implementation for `{Self} % {Rhs}`"
)]
#[doc(alias = "%")]
+#[const_trait]
pub trait Rem<Rhs = Self> {
/// The resulting type after applying the `%` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -682,6 +664,7 @@ rem_impl_float! { f32 f64 }
#[lang = "neg"]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(alias = "-")]
+#[const_trait]
pub trait Neg {
/// The resulting type after applying the `-` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -755,6 +738,7 @@ neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "+")]
#[doc(alias = "+=")]
+#[const_trait]
pub trait AddAssign<Rhs = Self> {
/// Performs the `+=` operation.
///
@@ -822,6 +806,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "-")]
#[doc(alias = "-=")]
+#[const_trait]
pub trait SubAssign<Rhs = Self> {
/// Performs the `-=` operation.
///
@@ -880,6 +865,7 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "*")]
#[doc(alias = "*=")]
+#[const_trait]
pub trait MulAssign<Rhs = Self> {
/// Performs the `*=` operation.
///
@@ -938,6 +924,7 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "/")]
#[doc(alias = "/=")]
+#[const_trait]
pub trait DivAssign<Rhs = Self> {
/// Performs the `/=` operation.
///
@@ -999,6 +986,7 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
)]
#[doc(alias = "%")]
#[doc(alias = "%=")]
+#[const_trait]
pub trait RemAssign<Rhs = Self> {
/// Performs the `%=` operation.
///
diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs
index 7c664226f..327009801 100644
--- a/library/core/src/ops/bit.rs
+++ b/library/core/src/ops/bit.rs
@@ -31,6 +31,7 @@
#[lang = "not"]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(alias = "!")]
+#[const_trait]
pub trait Not {
/// The resulting type after applying the `!` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -143,6 +144,7 @@ impl const Not for ! {
message = "no implementation for `{Self} & {Rhs}`",
label = "no implementation for `{Self} & {Rhs}`"
)]
+#[const_trait]
pub trait BitAnd<Rhs = Self> {
/// The resulting type after applying the `&` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -244,6 +246,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} | {Rhs}`",
label = "no implementation for `{Self} | {Rhs}`"
)]
+#[const_trait]
pub trait BitOr<Rhs = Self> {
/// The resulting type after applying the `|` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -345,6 +348,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} ^ {Rhs}`",
label = "no implementation for `{Self} ^ {Rhs}`"
)]
+#[const_trait]
pub trait BitXor<Rhs = Self> {
/// The resulting type after applying the `^` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -445,6 +449,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} << {Rhs}`",
label = "no implementation for `{Self} << {Rhs}`"
)]
+#[const_trait]
pub trait Shl<Rhs = Self> {
/// The resulting type after applying the `<<` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -564,6 +569,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 }
message = "no implementation for `{Self} >> {Rhs}`",
label = "no implementation for `{Self} >> {Rhs}`"
)]
+#[const_trait]
pub trait Shr<Rhs = Self> {
/// The resulting type after applying the `>>` operator.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -692,6 +698,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
message = "no implementation for `{Self} &= {Rhs}`",
label = "no implementation for `{Self} &= {Rhs}`"
)]
+#[const_trait]
pub trait BitAndAssign<Rhs = Self> {
/// Performs the `&=` operation.
///
@@ -764,6 +771,7 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} |= {Rhs}`",
label = "no implementation for `{Self} |= {Rhs}`"
)]
+#[const_trait]
pub trait BitOrAssign<Rhs = Self> {
/// Performs the `|=` operation.
///
@@ -836,6 +844,7 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} ^= {Rhs}`",
label = "no implementation for `{Self} ^= {Rhs}`"
)]
+#[const_trait]
pub trait BitXorAssign<Rhs = Self> {
/// Performs the `^=` operation.
///
@@ -906,6 +915,7 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
message = "no implementation for `{Self} <<= {Rhs}`",
label = "no implementation for `{Self} <<= {Rhs}`"
)]
+#[const_trait]
pub trait ShlAssign<Rhs = Self> {
/// Performs the `<<=` operation.
///
@@ -989,6 +999,7 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
message = "no implementation for `{Self} >>= {Rhs}`",
label = "no implementation for `{Self} >>= {Rhs}`"
)]
+#[const_trait]
pub trait ShrAssign<Rhs = Self> {
/// Performs the `>>=` operation.
///
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index b1f5559dc..72ebe653c 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -95,7 +95,8 @@ pub enum ControlFlow<B, C = ()> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-impl<B, C> ops::Try for ControlFlow<B, C> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<B, C> const ops::Try for ControlFlow<B, C> {
type Output = C;
type Residual = ControlFlow<B, convert::Infallible>;
@@ -114,7 +115,8 @@ impl<B, C> ops::Try for ControlFlow<B, C> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-impl<B, C> ops::FromResidual for ControlFlow<B, C> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<B, C> const ops::FromResidual for ControlFlow<B, C> {
#[inline]
fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
match residual {
@@ -124,7 +126,8 @@ impl<B, C> ops::FromResidual for ControlFlow<B, C> {
}
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-impl<B, C> ops::Residual<C> for ControlFlow<B, convert::Infallible> {
+#[rustc_const_unstable(feature = "const_try", issue = "74935")]
+impl<B, C> const ops::Residual<C> for ControlFlow<B, convert::Infallible> {
type TryType = ControlFlow<B, C>;
}
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index d68932402..4f4c99c4a 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -61,6 +61,7 @@
#[doc(alias = "&*")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Deref"]
+#[cfg_attr(not(bootstrap), const_trait)]
pub trait Deref {
/// The resulting type after dereferencing.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -169,6 +170,7 @@ impl<T: ?Sized> const Deref for &mut T {
#[lang = "deref_mut"]
#[doc(alias = "*")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[const_trait]
pub trait DerefMut: Deref {
/// Mutably dereferences the value.
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs
index aa654aa55..a2c3d978c 100644
--- a/library/core/src/ops/drop.rs
+++ b/library/core/src/ops/drop.rs
@@ -134,6 +134,7 @@
/// these types cannot have destructors.
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[const_trait]
pub trait Drop {
/// Executes the destructor for this type.
///
@@ -156,7 +157,7 @@ pub trait Drop {
/// handled by the compiler, but when using unsafe code, can sometimes occur
/// unintentionally, particularly when using [`ptr::drop_in_place`].
///
- /// [E0040]: ../../error-index.html#E0040
+ /// [E0040]: ../../error_codes/E0040.html
/// [`panic!`]: crate::panic!
/// [`mem::drop`]: drop
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place
diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs
index c5a194b7d..2e0a752c8 100644
--- a/library/core/src/ops/function.rs
+++ b/library/core/src/ops/function.rs
@@ -71,6 +71,7 @@
)]
#[fundamental] // so that regex can rely that `&str: !FnMut`
#[must_use = "closures are lazy and do nothing unless called"]
+#[cfg_attr(not(bootstrap), const_trait)]
pub trait Fn<Args>: FnMut<Args> {
/// Performs the call operation.
#[unstable(feature = "fn_traits", issue = "29625")]
@@ -158,6 +159,7 @@ pub trait Fn<Args>: FnMut<Args> {
)]
#[fundamental] // so that regex can rely that `&str: !FnMut`
#[must_use = "closures are lazy and do nothing unless called"]
+#[cfg_attr(not(bootstrap), const_trait)]
pub trait FnMut<Args>: FnOnce<Args> {
/// Performs the call operation.
#[unstable(feature = "fn_traits", issue = "29625")]
@@ -237,6 +239,7 @@ pub trait FnMut<Args>: FnOnce<Args> {
)]
#[fundamental] // so that regex can rely that `&str: !FnMut`
#[must_use = "closures are lazy and do nothing unless called"]
+#[cfg_attr(not(bootstrap), const_trait)]
pub trait FnOnce<Args> {
/// The returned type after the call operator is used.
#[lang = "fn_once_output"]
@@ -250,9 +253,10 @@ pub trait FnOnce<Args> {
mod impls {
#[stable(feature = "rust1", since = "1.0.0")]
- impl<A, F: ?Sized> Fn<A> for &F
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A, F: ?Sized> const Fn<A> for &F
where
- F: Fn<A>,
+ F: ~const Fn<A>,
{
extern "rust-call" fn call(&self, args: A) -> F::Output {
(**self).call(args)
@@ -260,9 +264,10 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl<A, F: ?Sized> FnMut<A> for &F
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A, F: ?Sized> const FnMut<A> for &F
where
- F: Fn<A>,
+ F: ~const Fn<A>,
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(**self).call(args)
@@ -270,9 +275,10 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl<A, F: ?Sized> FnOnce<A> for &F
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A, F: ?Sized> const FnOnce<A> for &F
where
- F: Fn<A>,
+ F: ~const Fn<A>,
{
type Output = F::Output;
@@ -282,9 +288,10 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl<A, F: ?Sized> FnMut<A> for &mut F
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A, F: ?Sized> const FnMut<A> for &mut F
where
- F: FnMut<A>,
+ F: ~const FnMut<A>,
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(*self).call_mut(args)
@@ -292,9 +299,10 @@ mod impls {
}
#[stable(feature = "rust1", since = "1.0.0")]
- impl<A, F: ?Sized> FnOnce<A> for &mut F
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A, F: ?Sized> const FnOnce<A> for &mut F
where
- F: FnMut<A>,
+ F: ~const FnMut<A>,
{
type Output = F::Output;
extern "rust-call" fn call_once(self, args: A) -> F::Output {
diff --git a/library/core/src/ops/generator.rs b/library/core/src/ops/generator.rs
index b651b7b23..fee4beb1e 100644
--- a/library/core/src/ops/generator.rs
+++ b/library/core/src/ops/generator.rs
@@ -83,7 +83,6 @@ pub trait Generator<R = ()> {
/// `return` statement or implicitly as the last expression of a generator
/// literal. For example futures would use this as `Result<T, E>` as it
/// represents a completed future.
- #[lang = "generator_return"]
type Return;
/// Resumes the execution of this generator.
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
index e2e569cb7..dd4e3ac1c 100644
--- a/library/core/src/ops/index.rs
+++ b/library/core/src/ops/index.rs
@@ -55,6 +55,7 @@
#[doc(alias = "]")]
#[doc(alias = "[")]
#[doc(alias = "[]")]
+#[cfg_attr(not(bootstrap), const_trait)]
pub trait Index<Idx: ?Sized> {
/// The returned type after indexing.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -163,6 +164,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind
#[doc(alias = "[")]
#[doc(alias = "]")]
#[doc(alias = "[]")]
+#[cfg_attr(not(bootstrap), const_trait)]
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
/// Performs the mutable indexing (`container[index]`) operation.
///
diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs
new file mode 100644
index 000000000..3e06776d2
--- /dev/null
+++ b/library/core/src/ops/index_range.rs
@@ -0,0 +1,171 @@
+use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub};
+use crate::iter::{FusedIterator, TrustedLen};
+
+/// Like a `Range<usize>`, but with a safety invariant that `start <= end`.
+///
+/// This means that `end - start` cannot overflow, allowing some μoptimizations.
+///
+/// (Normal `Range` code needs to handle degenerate ranges like `10..0`,
+/// which takes extra checks compared to only handling the canonical form.)
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) struct IndexRange {
+ start: usize,
+ end: usize,
+}
+
+impl IndexRange {
+ /// # Safety
+ /// - `start <= end`
+ #[inline]
+ pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self {
+ // SAFETY: comparisons on usize are pure
+ unsafe {
+ assert_unsafe_precondition!(
+ "IndexRange::new_unchecked requires `start <= end`",
+ (start: usize, end: usize) => start <= end
+ )
+ };
+ IndexRange { start, end }
+ }
+
+ #[inline]
+ pub const fn zero_to(end: usize) -> Self {
+ IndexRange { start: 0, end }
+ }
+
+ #[inline]
+ pub const fn start(&self) -> usize {
+ self.start
+ }
+
+ #[inline]
+ pub const fn end(&self) -> usize {
+ self.end
+ }
+
+ #[inline]
+ pub const fn len(&self) -> usize {
+ // SAFETY: By invariant, this cannot wrap
+ unsafe { unchecked_sub(self.end, self.start) }
+ }
+
+ /// # Safety
+ /// - Can only be called when `start < end`, aka when `len > 0`.
+ #[inline]
+ unsafe fn next_unchecked(&mut self) -> usize {
+ debug_assert!(self.start < self.end);
+
+ let value = self.start;
+ // SAFETY: The range isn't empty, so this cannot overflow
+ self.start = unsafe { unchecked_add(value, 1) };
+ value
+ }
+
+ /// # Safety
+ /// - Can only be called when `start < end`, aka when `len > 0`.
+ #[inline]
+ unsafe fn next_back_unchecked(&mut self) -> usize {
+ debug_assert!(self.start < self.end);
+
+ // SAFETY: The range isn't empty, so this cannot overflow
+ let value = unsafe { unchecked_sub(self.end, 1) };
+ self.end = value;
+ value
+ }
+
+ /// Removes the first `n` items from this range, returning them as an `IndexRange`.
+ /// If there are fewer than `n`, then the whole range is returned and
+ /// `self` is left empty.
+ ///
+ /// This is designed to help implement `Iterator::advance_by`.
+ #[inline]
+ pub fn take_prefix(&mut self, n: usize) -> Self {
+ let mid = if n <= self.len() {
+ // SAFETY: We just checked that this will be between start and end,
+ // and thus the addition cannot overflow.
+ unsafe { unchecked_add(self.start, n) }
+ } else {
+ self.end
+ };
+ let prefix = Self { start: self.start, end: mid };
+ self.start = mid;
+ prefix
+ }
+
+ /// Removes the last `n` items from this range, returning them as an `IndexRange`.
+ /// If there are fewer than `n`, then the whole range is returned and
+ /// `self` is left empty.
+ ///
+ /// This is designed to help implement `Iterator::advance_back_by`.
+ #[inline]
+ pub fn take_suffix(&mut self, n: usize) -> Self {
+ let mid = if n <= self.len() {
+ // SAFETY: We just checked that this will be between start and end,
+ // and thus the addition cannot overflow.
+ unsafe { unchecked_sub(self.end, n) }
+ } else {
+ self.start
+ };
+ let suffix = Self { start: mid, end: self.end };
+ self.end = mid;
+ suffix
+ }
+}
+
+impl Iterator for IndexRange {
+ type Item = usize;
+
+ #[inline]
+ fn next(&mut self) -> Option<usize> {
+ if self.len() > 0 {
+ // SAFETY: We just checked that the range is non-empty
+ unsafe { Some(self.next_unchecked()) }
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+ let original_len = self.len();
+ self.take_prefix(n);
+ if n > original_len { Err(original_len) } else { Ok(()) }
+ }
+}
+
+impl DoubleEndedIterator for IndexRange {
+ #[inline]
+ fn next_back(&mut self) -> Option<usize> {
+ if self.len() > 0 {
+ // SAFETY: We just checked that the range is non-empty
+ unsafe { Some(self.next_back_unchecked()) }
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+ let original_len = self.len();
+ self.take_suffix(n);
+ if n > original_len { Err(original_len) } else { Ok(()) }
+ }
+}
+
+impl ExactSizeIterator for IndexRange {
+ #[inline]
+ fn len(&self) -> usize {
+ self.len()
+ }
+}
+
+// SAFETY: Because we only deal in `usize`, our `len` is always perfect.
+unsafe impl TrustedLen for IndexRange {}
+
+impl FusedIterator for IndexRange {}
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 31c1a1d09..a5e5b13b3 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -146,6 +146,7 @@ mod drop;
mod function;
mod generator;
mod index;
+mod index_range;
mod range;
mod try_trait;
mod unsize;
@@ -178,6 +179,8 @@ pub use self::index::{Index, IndexMut};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
+pub(crate) use self::index_range::IndexRange;
+
#[stable(feature = "inclusive_range", since = "1.26.0")]
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index a3b148473..d29ae3561 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -677,7 +677,7 @@ pub enum Bound<T> {
impl<T> Bound<T> {
/// Converts from `&Bound<T>` to `Bound<&T>`.
#[inline]
- #[unstable(feature = "bound_as_ref", issue = "80996")]
+ #[stable(feature = "bound_as_ref_shared", since = "1.65.0")]
pub fn as_ref(&self) -> Bound<&T> {
match *self {
Included(ref x) => Included(x),
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 02f7f62bf..84a690468 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -128,7 +128,8 @@ use crate::ops::ControlFlow;
)]
#[doc(alias = "?")]
#[lang = "Try"]
-pub trait Try: FromResidual {
+#[const_trait]
+pub trait Try: ~const FromResidual {
/// The type of the value produced by `?` when *not* short-circuiting.
#[unstable(feature = "try_trait_v2", issue = "84277")]
type Output;
@@ -232,7 +233,7 @@ pub trait Try: FromResidual {
message = "the `?` operator can only be used on `Result`s, not `Option`s, \
in {ItemContext} that returns `Result`",
label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`",
- enclosing_scope = "this function returns a `Result`"
+ parent_label = "this function returns a `Result`"
),
on(
all(
@@ -245,7 +246,7 @@ pub trait Try: FromResidual {
message = "the `?` operator can only be used on `Result`s \
in {ItemContext} that returns `Result`",
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
- enclosing_scope = "this function returns a `Result`"
+ parent_label = "this function returns a `Result`"
),
on(
all(
@@ -256,7 +257,7 @@ pub trait Try: FromResidual {
message = "the `?` operator can only be used on `Option`s, not `Result`s, \
in {ItemContext} that returns `Option`",
label = "use `.ok()?` if you want to discard the `{R}` error information",
- enclosing_scope = "this function returns an `Option`"
+ parent_label = "this function returns an `Option`"
),
on(
all(
@@ -268,7 +269,7 @@ pub trait Try: FromResidual {
message = "the `?` operator can only be used on `Option`s \
in {ItemContext} that returns `Option`",
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
- enclosing_scope = "this function returns an `Option`"
+ parent_label = "this function returns an `Option`"
),
on(
all(
@@ -279,7 +280,7 @@ pub trait Try: FromResidual {
message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
- enclosing_scope = "this function returns a `ControlFlow`",
+ parent_label = "this function returns a `ControlFlow`",
note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
),
on(
@@ -291,7 +292,7 @@ pub trait Try: FromResidual {
message = "the `?` operator can only be used on `ControlFlow`s \
in {ItemContext} that returns `ControlFlow`",
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
- enclosing_scope = "this function returns a `ControlFlow`",
+ parent_label = "this function returns a `ControlFlow`",
),
on(
all(from_desugaring = "QuestionMark"),
@@ -299,11 +300,12 @@ pub trait Try: FromResidual {
that returns `Result` or `Option` \
(or another type that implements `{FromResidual}`)",
label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
- enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
+ parent_label = "this function should return `Result` or `Option` to accept `?`"
),
)]
#[rustc_diagnostic_item = "FromResidual"]
#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[const_trait]
pub trait FromResidual<R = <Self as Try>::Residual> {
/// Constructs the type from a compatible `Residual` type.
///
@@ -356,10 +358,11 @@ where
/// and in the other direction,
/// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+#[const_trait]
pub trait Residual<O> {
/// The "return" type of this meta-function.
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
- type TryType: Try<Output = O, Residual = Self>;
+ type TryType: ~const Try<Output = O, Residual = Self>;
}
#[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
@@ -376,16 +379,19 @@ pub(crate) type ChangeOutputType<T, V> = <<T as Try>::Residual as Residual<V>>::
pub(crate) struct NeverShortCircuit<T>(pub T);
impl<T> NeverShortCircuit<T> {
- /// Wrap a binary `FnMut` to return its result wrapped in a `NeverShortCircuit`.
+ /// Implementation for building `ConstFnMutClosure` for wrapping the output of a ~const FnMut in a `NeverShortCircuit`.
#[inline]
- pub fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
- move |a, b| NeverShortCircuit(f(a, b))
+ pub const fn wrap_mut_2_imp<A, B, F: ~const FnMut(A, B) -> T>(
+ f: &mut F,
+ (a, b): (A, B),
+ ) -> NeverShortCircuit<T> {
+ NeverShortCircuit(f(a, b))
}
}
pub(crate) enum NeverShortCircuitResidual {}
-impl<T> Try for NeverShortCircuit<T> {
+impl<T> const Try for NeverShortCircuit<T> {
type Output = T;
type Residual = NeverShortCircuitResidual;
@@ -400,14 +406,14 @@ impl<T> Try for NeverShortCircuit<T> {
}
}
-impl<T> FromResidual for NeverShortCircuit<T> {
+impl<T> const FromResidual for NeverShortCircuit<T> {
#[inline]
fn from_residual(never: NeverShortCircuitResidual) -> Self {
match never {}
}
}
-impl<T> Residual<T> for NeverShortCircuitResidual {
+impl<T> const Residual<T> for NeverShortCircuitResidual {
type TryType = NeverShortCircuit<T>;
}
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index bca73cb77..f284b4359 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -559,22 +559,25 @@ impl<T> Option<T> {
/// # Examples
///
/// ```
- /// #![feature(is_some_with)]
+ /// #![feature(is_some_and)]
///
/// let x: Option<u32> = Some(2);
- /// assert_eq!(x.is_some_and(|&x| x > 1), true);
+ /// assert_eq!(x.is_some_and(|x| x > 1), true);
///
/// let x: Option<u32> = Some(0);
- /// assert_eq!(x.is_some_and(|&x| x > 1), false);
+ /// assert_eq!(x.is_some_and(|x| x > 1), false);
///
/// let x: Option<u32> = None;
- /// assert_eq!(x.is_some_and(|&x| x > 1), false);
+ /// assert_eq!(x.is_some_and(|x| x > 1), false);
/// ```
#[must_use]
#[inline]
- #[unstable(feature = "is_some_with", issue = "93050")]
- pub fn is_some_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
- matches!(self, Some(x) if f(x))
+ #[unstable(feature = "is_some_and", issue = "93050")]
+ pub fn is_some_and(self, f: impl FnOnce(T) -> bool) -> bool {
+ match self {
+ None => false,
+ Some(x) => f(x),
+ }
}
/// Returns `true` if the option is a [`None`] value.
@@ -834,19 +837,12 @@ impl<T> Option<T> {
///
/// # Examples
///
- /// Converts a string to an integer, turning poorly-formed strings
- /// into 0 (the default value for integers). [`parse`] converts
- /// a string to any other type that implements [`FromStr`], returning
- /// [`None`] on error.
- ///
/// ```
- /// let good_year_from_input = "1909";
- /// let bad_year_from_input = "190blarg";
- /// let good_year = good_year_from_input.parse().ok().unwrap_or_default();
- /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default();
+ /// let x: Option<u32> = None;
+ /// let y: Option<u32> = Some(12);
///
- /// assert_eq!(1909, good_year);
- /// assert_eq!(0, bad_year);
+ /// assert_eq!(x.unwrap_or_default(), 0);
+ /// assert_eq!(y.unwrap_or_default(), 12);
/// ```
///
/// [default value]: Default::default
@@ -1189,6 +1185,12 @@ impl<T> Option<T> {
/// Returns [`None`] if the option is [`None`], otherwise returns `optb`.
///
+ /// Arguments passed to `and` are eagerly evaluated; if you are passing the
+ /// result of a function call, it is recommended to use [`and_then`], which is
+ /// lazily evaluated.
+ ///
+ /// [`and_then`]: Option::and_then
+ ///
/// # Examples
///
/// ```
@@ -1711,8 +1713,6 @@ impl<T, U> Option<(T, U)> {
/// # Examples
///
/// ```
- /// #![feature(unzip_option)]
- ///
/// let x = Some((1, "hi"));
/// let y = None::<(u8, u32)>;
///
@@ -1720,8 +1720,13 @@ impl<T, U> Option<(T, U)> {
/// assert_eq!(y.unzip(), (None, None));
/// ```
#[inline]
- #[unstable(feature = "unzip_option", issue = "87800", reason = "recently added")]
- pub const fn unzip(self) -> (Option<T>, Option<U>) {
+ #[stable(feature = "unzip_option", since = "1.66.0")]
+ #[rustc_const_unstable(feature = "const_option", issue = "67441")]
+ pub const fn unzip(self) -> (Option<T>, Option<U>)
+ where
+ T: ~const Destruct,
+ U: ~const Destruct,
+ {
match self {
Some((a, b)) => (Some(a), Some(b)),
None => (None, None),
@@ -2315,7 +2320,8 @@ impl<T> ops::FromResidual<ops::Yeet<()>> for Option<T> {
}
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-impl<T> ops::Residual<T> for Option<convert::Infallible> {
+#[rustc_const_unstable(feature = "const_try", issue = "74935")]
+impl<T> const ops::Residual<T> for Option<convert::Infallible> {
type TryType = Option<T>;
}
diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs
index 8eefd9ff2..6dcf23dde 100644
--- a/library/core/src/panic/location.rs
+++ b/library/core/src/panic/location.rs
@@ -123,8 +123,9 @@ impl<'a> Location<'a> {
/// ```
#[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
+ #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")]
#[inline]
- pub fn file(&self) -> &str {
+ pub const fn file(&self) -> &str {
self.file
}
@@ -147,8 +148,9 @@ impl<'a> Location<'a> {
/// ```
#[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
+ #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")]
#[inline]
- pub fn line(&self) -> u32 {
+ pub const fn line(&self) -> u32 {
self.line
}
@@ -171,8 +173,9 @@ impl<'a> Location<'a> {
/// ```
#[must_use]
#[stable(feature = "panic_col", since = "1.25.0")]
+ #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")]
#[inline]
- pub fn column(&self) -> u32 {
+ pub const fn column(&self) -> u32 {
self.col
}
}
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 7a575a88e..a9de7c94e 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -29,6 +29,73 @@
use crate::fmt;
use crate::panic::{Location, PanicInfo};
+// First we define the two main entry points that all panics go through.
+// In the end both are just convenience wrappers around `panic_impl`.
+
+/// The entry point for panicking with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `panic!()` has as low an impact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
+#[cold]
+// If panic_immediate_abort, inline the abort call,
+// otherwise avoid inlining because of it is cold path.
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[track_caller]
+#[lang = "panic_fmt"] // needed for const-evaluated panics
+#[rustc_do_not_const_check] // hooked by const-eval
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
+pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
+ if cfg!(feature = "panic_immediate_abort") {
+ super::intrinsics::abort()
+ }
+
+ // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
+ // that gets resolved to the `#[panic_handler]` function.
+ extern "Rust" {
+ #[lang = "panic_impl"]
+ fn panic_impl(pi: &PanicInfo<'_>) -> !;
+ }
+
+ let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);
+
+ // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
+ unsafe { panic_impl(&pi) }
+}
+
+/// Like panic_fmt, but without unwinding and track_caller to reduce the impact on codesize.
+/// Also just works on `str`, as a `fmt::Arguments` needs more space to be passed.
+#[cold]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
+#[cfg_attr(not(bootstrap), rustc_nounwind)]
+#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
+pub fn panic_str_nounwind(msg: &'static str) -> ! {
+ if cfg!(feature = "panic_immediate_abort") {
+ super::intrinsics::abort()
+ }
+
+ // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
+ // that gets resolved to the `#[panic_handler]` function.
+ extern "Rust" {
+ #[lang = "panic_impl"]
+ fn panic_impl(pi: &PanicInfo<'_>) -> !;
+ }
+
+ // PanicInfo with the `can_unwind` flag set to false forces an abort.
+ let pieces = [msg];
+ let fmt = fmt::Arguments::new_v1(&pieces, &[]);
+ let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
+
+ // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
+ unsafe { panic_impl(&pi) }
+}
+
+// Next we define a bunch of higher-level wrappers that all bottom out in the two core functions
+// above.
+
/// The underlying implementation of libcore's `panic!` macro when no formatting is used.
#[cold]
// never inline unless panic_immediate_abort to avoid code
@@ -84,62 +151,17 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
panic!("index out of bounds: the len is {len} but the index is {index}")
}
-// This function is called directly by the codegen backend, and must not have
-// any extra arguments (including those synthesized by track_caller).
+/// Panic because we cannot unwind out of a function.
+///
+/// This function is called directly by the codegen backend, and must not have
+/// any extra arguments (including those synthesized by track_caller).
#[cold]
#[inline(never)]
#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
+#[cfg_attr(not(bootstrap), rustc_nounwind)]
+#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
fn panic_no_unwind() -> ! {
- if cfg!(feature = "panic_immediate_abort") {
- super::intrinsics::abort()
- }
-
- // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
- // that gets resolved to the `#[panic_handler]` function.
- extern "Rust" {
- #[lang = "panic_impl"]
- fn panic_impl(pi: &PanicInfo<'_>) -> !;
- }
-
- // PanicInfo with the `can_unwind` flag set to false forces an abort.
- let fmt = format_args!("panic in a function that cannot unwind");
- let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
-
- // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
- unsafe { panic_impl(&pi) }
-}
-
-/// The entry point for panicking with a formatted message.
-///
-/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `panic!()` has as low an impact
-/// on (e.g.) the inlining of other functions as possible), by moving
-/// the actual formatting into this shared place.
-#[cold]
-// If panic_immediate_abort, inline the abort call,
-// otherwise avoid inlining because of it is cold path.
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[track_caller]
-#[lang = "panic_fmt"] // needed for const-evaluated panics
-#[rustc_do_not_const_check] // hooked by const-eval
-#[rustc_const_unstable(feature = "core_panic", issue = "none")]
-pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
- if cfg!(feature = "panic_immediate_abort") {
- super::intrinsics::abort()
- }
-
- // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
- // that gets resolved to the `#[panic_handler]` function.
- extern "Rust" {
- #[lang = "panic_impl"]
- fn panic_impl(pi: &PanicInfo<'_>) -> !;
- }
-
- let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);
-
- // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
- unsafe { panic_impl(&pi) }
+ panic_str_nounwind("panic in a function that cannot unwind")
}
/// This function is used instead of panic_fmt in const eval.
@@ -190,11 +212,11 @@ pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
right: &str,
args: Option<fmt::Arguments<'_>>,
) -> ! {
- // Use the Display implementation to display the pattern.
+ // The pattern is a string so it can be displayed directly.
struct Pattern<'a>(&'a str);
impl fmt::Debug for Pattern<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self.0, f)
+ f.write_str(self.0)
}
}
assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index b8e546164..331714a99 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -611,7 +611,19 @@ mod prim_pointer {}
///
/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
/// an array. Indeed, this provides most of the API for working with arrays.
-/// Slices have a dynamic size and do not coerce to arrays.
+///
+/// Slices have a dynamic size and do not coerce to arrays. Instead, use
+/// `slice.try_into().unwrap()` or `<ArrayType>::try_from(slice).unwrap()`.
+///
+/// Array's `try_from(slice)` implementations (and the corresponding `slice.try_into()`
+/// array implementations) succeed if the input slice length is the same as the result
+/// array length. They optimize especially well when the optimizer can easily determine
+/// the slice length, e.g. `<[u8; 4]>::try_from(&slice[4..8]).unwrap()`. Array implements
+/// [TryFrom](crate::convert::TryFrom) returning:
+///
+/// - `[T; N]` copies from the slice's elements
+/// - `&[T; N]` references the original slice's elements
+/// - `&mut [T; N]` references the original slice's elements
///
/// You can move elements out of an array with a [slice pattern]. If you want
/// one element, see [`mem::replace`].
@@ -640,6 +652,15 @@ mod prim_pointer {}
/// for x in &array { }
/// ```
///
+/// You can use `<ArrayType>::try_from(slice)` or `slice.try_into()` to get an array from
+/// a slice:
+///
+/// ```
+/// let bytes: [u8; 3] = [1, 0, 2];
+/// assert_eq!(1, u16::from_le_bytes(<[u8; 2]>::try_from(&bytes[0..2]).unwrap()));
+/// assert_eq!(512, u16::from_le_bytes(bytes[1..3].try_into().unwrap()));
+/// ```
+///
/// You can use a [slice pattern] to move elements out of an array:
///
/// ```
@@ -801,11 +822,53 @@ mod prim_array {}
/// assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>());
/// assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());
/// ```
+///
+/// ## Trait Implementations
+///
+/// Some traits are implemented for slices if the element type implements
+/// that trait. This includes [`Eq`], [`Hash`] and [`Ord`].
+///
+/// ## Iteration
+///
+/// The slices implement `IntoIterator`. The iterator yields references to the
+/// slice elements.
+///
+/// ```
+/// let numbers: &[i32] = &[0, 1, 2];
+/// for n in numbers {
+/// println!("{n} is a number!");
+/// }
+/// ```
+///
+/// The mutable slice yields mutable references to the elements:
+///
+/// ```
+/// let mut scores: &mut [i32] = &mut [7, 8, 9];
+/// for score in scores {
+/// *score += 1;
+/// }
+/// ```
+///
+/// This iterator yields mutable references to the slice's elements, so while
+/// the element type of the slice is `i32`, the element type of the iterator is
+/// `&mut i32`.
+///
+/// * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default
+/// iterators.
+/// * Further methods that return iterators are [`.split`], [`.splitn`],
+/// [`.chunks`], [`.windows`] and more.
+///
+/// [`Hash`]: core::hash::Hash
+/// [`.iter`]: slice::iter
+/// [`.iter_mut`]: slice::iter_mut
+/// [`.split`]: slice::split
+/// [`.splitn`]: slice::splitn
+/// [`.chunks`]: slice::chunks
+/// [`.windows`]: slice::windows
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice {}
#[doc(primitive = "str")]
-//
/// String slices.
///
/// *[See also the `std::str` module](crate::str).*
@@ -816,19 +879,22 @@ mod prim_slice {}
///
/// String slices are always valid UTF-8.
///
-/// # Examples
+/// # Basic Usage
///
/// String literals are string slices:
///
/// ```
-/// let hello = "Hello, world!";
-///
-/// // with an explicit type annotation
-/// let hello: &'static str = "Hello, world!";
+/// let hello_world = "Hello, World!";
/// ```
///
-/// They are `'static` because they're stored directly in the final binary, and
-/// so will be valid for the `'static` duration.
+/// Here we have declared a string slice initialized with a string literal.
+/// String literals have a static lifetime, which means the string `hello_world`
+/// is guaranteed to be valid for the duration of the entire program.
+/// We can explicitly specify `hello_world`'s lifetime as well:
+///
+/// ```
+/// let hello_world: &'static str = "Hello, world!";
+/// ```
///
/// # Representation
///
@@ -996,7 +1062,7 @@ impl<T> (T,) {}
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), doc(fake_variadic))]
+#[doc(fake_variadic)]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Clone> Clone for (T,) {
fn clone(&self) -> Self {
@@ -1007,7 +1073,7 @@ impl<T: Clone> Clone for (T,) {
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), doc(fake_variadic))]
+#[doc(fake_variadic)]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Copy> Copy for (T,) {
// empty
@@ -1178,7 +1244,7 @@ mod prim_usize {}
#[doc(alias = "&")]
#[doc(alias = "&mut")]
//
-/// References, both shared and mutable.
+/// References, `&T` and `&mut T`.
///
/// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut`
/// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or
@@ -1484,13 +1550,12 @@ mod prim_fn {}
// Required to make auto trait impls render.
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
#[doc(hidden)]
-#[cfg(not(bootstrap))]
impl<Ret, T> fn(T) -> Ret {}
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), doc(fake_variadic))]
+#[doc(fake_variadic)]
/// This trait is implemented on function pointers with any number of arguments.
impl<Ret, T> Clone for fn(T) -> Ret {
fn clone(&self) -> Self {
@@ -1501,7 +1566,7 @@ impl<Ret, T> Clone for fn(T) -> Ret {
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), doc(fake_variadic))]
+#[doc(fake_variadic)]
/// This trait is implemented on function pointers with any number of arguments.
impl<Ret, T> Copy for fn(T) -> Ret {
// empty
diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/ptr/alignment.rs
index fcfa95120..1390e09dd 100644
--- a/library/core/src/mem/valid_align.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -1,4 +1,5 @@
-use crate::convert::TryFrom;
+use crate::convert::{TryFrom, TryInto};
+use crate::intrinsics::assert_unsafe_precondition;
use crate::num::NonZeroUsize;
use crate::{cmp, fmt, hash, mem, num};
@@ -7,16 +8,62 @@ use crate::{cmp, fmt, hash, mem, num};
///
/// Note that particularly large alignments, while representable in this type,
/// are likely not to be supported by actual allocators and linkers.
-#[derive(Copy, Clone)]
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(transparent)]
-pub(crate) struct ValidAlign(ValidAlignEnum);
+pub struct Alignment(AlignmentEnum);
-// ValidAlign is `repr(usize)`, but via extra steps.
-const _: () = assert!(mem::size_of::<ValidAlign>() == mem::size_of::<usize>());
-const _: () = assert!(mem::align_of::<ValidAlign>() == mem::align_of::<usize>());
+// Alignment is `repr(usize)`, but via extra steps.
+const _: () = assert!(mem::size_of::<Alignment>() == mem::size_of::<usize>());
+const _: () = assert!(mem::align_of::<Alignment>() == mem::align_of::<usize>());
-impl ValidAlign {
- /// Creates a `ValidAlign` from a power-of-two `usize`.
+fn _alignment_can_be_structurally_matched(a: Alignment) -> bool {
+ matches!(a, Alignment::MIN)
+}
+
+impl Alignment {
+ /// The smallest possible alignment, 1.
+ ///
+ /// All addresses are always aligned at least this much.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ptr_alignment_type)]
+ /// use std::ptr::Alignment;
+ ///
+ /// assert_eq!(Alignment::MIN.as_usize(), 1);
+ /// ```
+ #[unstable(feature = "ptr_alignment_type", issue = "102070")]
+ pub const MIN: Self = Self(AlignmentEnum::_Align1Shl0);
+
+ /// Returns the alignment for a type.
+ ///
+ /// This provides the same numerical value as [`mem::align_of`],
+ /// but in an `Alignment` instead of a `usize.
+ #[unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[inline]
+ pub const fn of<T>() -> Self {
+ // SAFETY: rustc ensures that type alignment is always a power of two.
+ unsafe { Alignment::new_unchecked(mem::align_of::<T>()) }
+ }
+
+ /// Creates an `Alignment` from a `usize`, or returns `None` if it's
+ /// not a power of two.
+ ///
+ /// Note that `0` is not a power of two, nor a valid alignment.
+ #[unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[inline]
+ pub const fn new(align: usize) -> Option<Self> {
+ if align.is_power_of_two() {
+ // SAFETY: Just checked it only has one bit set
+ Some(unsafe { Self::new_unchecked(align) })
+ } else {
+ None
+ }
+ }
+
+ /// Creates an `Alignment` from a power-of-two `usize`.
///
/// # Safety
///
@@ -24,88 +71,120 @@ impl ValidAlign {
///
/// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`.
/// It must *not* be zero.
+ #[unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
- pub(crate) const unsafe fn new_unchecked(align: usize) -> Self {
- debug_assert!(align.is_power_of_two());
+ pub const unsafe fn new_unchecked(align: usize) -> Self {
+ // SAFETY: Precondition passed to the caller.
+ unsafe {
+ assert_unsafe_precondition!(
+ "Alignment::new_unchecked requires a power of two",
+ (align: usize) => align.is_power_of_two()
+ )
+ };
// SAFETY: By precondition, this must be a power of two, and
// our variants encompass all possible powers of two.
- unsafe { mem::transmute::<usize, ValidAlign>(align) }
+ unsafe { mem::transmute::<usize, Alignment>(align) }
+ }
+
+ /// Returns the alignment as a [`usize`]
+ #[unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
+ #[inline]
+ pub const fn as_usize(self) -> usize {
+ self.0 as usize
}
+ /// Returns the alignment as a [`NonZeroUsize`]
+ #[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
- pub(crate) const fn as_nonzero(self) -> NonZeroUsize {
+ pub const fn as_nonzero(self) -> NonZeroUsize {
// SAFETY: All the discriminants are non-zero.
- unsafe { NonZeroUsize::new_unchecked(self.0 as usize) }
+ unsafe { NonZeroUsize::new_unchecked(self.as_usize()) }
}
- /// Returns the base 2 logarithm of the alignment.
+ /// Returns the base-2 logarithm of the alignment.
///
/// This is always exact, as `self` represents a power of two.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ptr_alignment_type)]
+ /// use std::ptr::Alignment;
+ ///
+ /// assert_eq!(Alignment::of::<u8>().log2(), 0);
+ /// assert_eq!(Alignment::new(1024).unwrap().log2(), 10);
+ /// ```
+ #[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
- pub(crate) fn log2(self) -> u32 {
+ pub fn log2(self) -> u32 {
self.as_nonzero().trailing_zeros()
}
}
-impl fmt::Debug for ValidAlign {
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+impl fmt::Debug for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2())
}
}
-impl TryFrom<NonZeroUsize> for ValidAlign {
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+impl TryFrom<NonZeroUsize> for Alignment {
type Error = num::TryFromIntError;
#[inline]
- fn try_from(align: NonZeroUsize) -> Result<ValidAlign, Self::Error> {
- if align.is_power_of_two() {
- // SAFETY: Just checked for power-of-two
- unsafe { Ok(ValidAlign::new_unchecked(align.get())) }
- } else {
- Err(num::TryFromIntError(()))
- }
+ fn try_from(align: NonZeroUsize) -> Result<Alignment, Self::Error> {
+ align.get().try_into()
}
}
-impl TryFrom<usize> for ValidAlign {
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+impl TryFrom<usize> for Alignment {
type Error = num::TryFromIntError;
#[inline]
- fn try_from(align: usize) -> Result<ValidAlign, Self::Error> {
- if align.is_power_of_two() {
- // SAFETY: Just checked for power-of-two
- unsafe { Ok(ValidAlign::new_unchecked(align)) }
- } else {
- Err(num::TryFromIntError(()))
- }
+ fn try_from(align: usize) -> Result<Alignment, Self::Error> {
+ Self::new(align).ok_or(num::TryFromIntError(()))
}
}
-impl cmp::Eq for ValidAlign {}
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+impl From<Alignment> for NonZeroUsize {
+ #[inline]
+ fn from(align: Alignment) -> NonZeroUsize {
+ align.as_nonzero()
+ }
+}
-impl cmp::PartialEq for ValidAlign {
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+impl From<Alignment> for usize {
#[inline]
- fn eq(&self, other: &Self) -> bool {
- self.as_nonzero() == other.as_nonzero()
+ fn from(align: Alignment) -> usize {
+ align.as_usize()
}
}
-impl cmp::Ord for ValidAlign {
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+impl cmp::Ord for Alignment {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_nonzero().cmp(&other.as_nonzero())
}
}
-impl cmp::PartialOrd for ValidAlign {
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+impl cmp::PartialOrd for Alignment {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
-impl hash::Hash for ValidAlign {
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+impl hash::Hash for Alignment {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_nonzero().hash(state)
@@ -113,15 +192,15 @@ impl hash::Hash for ValidAlign {
}
#[cfg(target_pointer_width = "16")]
-type ValidAlignEnum = ValidAlignEnum16;
+type AlignmentEnum = AlignmentEnum16;
#[cfg(target_pointer_width = "32")]
-type ValidAlignEnum = ValidAlignEnum32;
+type AlignmentEnum = AlignmentEnum32;
#[cfg(target_pointer_width = "64")]
-type ValidAlignEnum = ValidAlignEnum64;
+type AlignmentEnum = AlignmentEnum64;
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(u16)]
-enum ValidAlignEnum16 {
+enum AlignmentEnum16 {
_Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2,
@@ -140,9 +219,9 @@ enum ValidAlignEnum16 {
_Align1Shl15 = 1 << 15,
}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(u32)]
-enum ValidAlignEnum32 {
+enum AlignmentEnum32 {
_Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2,
@@ -177,9 +256,9 @@ enum ValidAlignEnum32 {
_Align1Shl31 = 1 << 31,
}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(u64)]
-enum ValidAlignEnum64 {
+enum AlignmentEnum64 {
_Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2,
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index e0655d68d..5a083227b 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -36,7 +36,10 @@ impl<T: ?Sized> *const T {
pub const fn is_null(self) -> bool {
// Compare via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
- (self as *const u8).guaranteed_eq(null())
+ match (self as *const u8).guaranteed_eq(null()) {
+ None => false,
+ Some(res) => res,
+ }
}
/// Casts to a pointer of another type.
@@ -95,8 +98,8 @@ impl<T: ?Sized> *const T {
///
/// This is a bit safer than `as` because it wouldn't silently change the type if the code is
/// refactored.
- #[unstable(feature = "ptr_const_cast", issue = "92675")]
- #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+ #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+ #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
pub const fn cast_mut(self) -> *mut T {
self as _
}
@@ -154,7 +157,7 @@ impl<T: ?Sized> *const T {
/// This is similar to `self as usize`, which semantically discards *provenance* and
/// *address-space* information. However, unlike `self as usize`, casting the returned address
/// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To
- /// properly restore the lost information and obtain a dereferencable pointer, use
+ /// properly restore the lost information and obtain a dereferenceable pointer, use
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
///
/// If using those APIs is not possible because there is no way to preserve a pointer with the
@@ -249,7 +252,7 @@ impl<T: ?Sized> *const T {
let offset = dest_addr.wrapping_sub(self_addr);
// This is the canonical desugarring of this operation
- self.cast::<u8>().wrapping_offset(offset).cast::<T>()
+ self.wrapping_byte_offset(offset)
}
/// Creates a new pointer by mapping `self`'s address to a new one.
@@ -559,6 +562,20 @@ impl<T: ?Sized> *const T {
from_raw_parts::<T>(self.cast::<u8>().wrapping_offset(count).cast::<()>(), metadata(self))
}
+ /// Masks out bits of the pointer according to a mask.
+ ///
+ /// This is convenience for `ptr.map_addr(|a| a & mask)`.
+ ///
+ /// For non-`Sized` pointees this operation changes only the data pointer,
+ /// leaving the metadata untouched.
+ #[unstable(feature = "ptr_mask", issue = "98290")]
+ #[must_use = "returns a new pointer rather than modifying its argument"]
+ #[inline(always)]
+ pub fn mask(self, mask: usize) -> *const T {
+ let this = intrinsics::ptr_mask(self.cast::<()>(), mask);
+ from_raw_parts::<T>(this, metadata(self))
+ }
+
/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes divided by `mem::size_of::<T>()`.
///
@@ -641,7 +658,7 @@ impl<T: ?Sized> *const T {
/// }
/// ```
#[stable(feature = "ptr_offset_from", since = "1.47.0")]
- #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
+ #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")]
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn offset_from(self, origin: *const T) -> isize
@@ -677,7 +694,7 @@ impl<T: ?Sized> *const T {
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///
/// This computes the same value that [`offset_from`](#method.offset_from)
- /// would compute, but with the added precondition that that the offset is
+ /// would compute, but with the added precondition that the offset is
/// guaranteed to be non-negative. This method is equivalent to
/// `usize::from(self.offset_from(origin)).unwrap_unchecked()`,
/// but it provides slightly more information to the optimizer, which can
@@ -740,9 +757,15 @@ impl<T: ?Sized> *const T {
where
T: Sized,
{
+ let this = self;
// SAFETY: The comparison has no side-effects, and the intrinsic
// does this check internally in the CTFE implementation.
- unsafe { assert_unsafe_precondition!(self >= origin) };
+ unsafe {
+ assert_unsafe_precondition!(
+ "ptr::sub_ptr requires `this >= origin`",
+ [T](this: *const T, origin: *const T) => this >= origin
+ )
+ };
let pointee_size = mem::size_of::<T>();
assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
@@ -752,20 +775,16 @@ impl<T: ?Sized> *const T {
/// Returns whether two pointers are guaranteed to be equal.
///
- /// At runtime this function behaves like `self == other`.
+ /// At runtime this function behaves like `Some(self == other)`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine equality of two pointers, so this function may
- /// spuriously return `false` for pointers that later actually turn out to be equal.
- /// But when it returns `true`, the pointers are guaranteed to be equal.
+ /// spuriously return `None` for pointers that later actually turn out to have its equality known.
+ /// But when it returns `Some`, the pointers' equality is guaranteed to be known.
///
- /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
- /// comparisons for which both functions return `false`.
- ///
- /// [`guaranteed_ne`]: #method.guaranteed_ne
- ///
- /// The return value may change depending on the compiler version and unsafe code must not
+ /// The return value may change from `Some` to `None` and vice versa depending on the compiler
+ /// version and unsafe code must not
/// rely on the result of this function for soundness. It is suggested to only use this function
- /// for performance optimizations where spurious `false` return values by this function do not
+ /// for performance optimizations where spurious `None` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
@@ -774,29 +793,28 @@ impl<T: ?Sized> *const T {
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
- pub const fn guaranteed_eq(self, other: *const T) -> bool
+ pub const fn guaranteed_eq(self, other: *const T) -> Option<bool>
where
T: Sized,
{
- intrinsics::ptr_guaranteed_eq(self, other)
+ match intrinsics::ptr_guaranteed_cmp(self as _, other as _) {
+ 2 => None,
+ other => Some(other == 1),
+ }
}
- /// Returns whether two pointers are guaranteed to be unequal.
+ /// Returns whether two pointers are guaranteed to be inequal.
///
- /// At runtime this function behaves like `self != other`.
+ /// At runtime this function behaves like `Some(self != other)`.
/// However, in some contexts (e.g., compile-time evaluation),
- /// it is not always possible to determine the inequality of two pointers, so this function may
- /// spuriously return `false` for pointers that later actually turn out to be unequal.
- /// But when it returns `true`, the pointers are guaranteed to be unequal.
- ///
- /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
- /// comparisons for which both functions return `false`.
- ///
- /// [`guaranteed_eq`]: #method.guaranteed_eq
+ /// it is not always possible to determine inequality of two pointers, so this function may
+ /// spuriously return `None` for pointers that later actually turn out to have its inequality known.
+ /// But when it returns `Some`, the pointers' inequality is guaranteed to be known.
///
- /// The return value may change depending on the compiler version and unsafe code must not
+ /// The return value may change from `Some` to `None` and vice versa depending on the compiler
+ /// version and unsafe code must not
/// rely on the result of this function for soundness. It is suggested to only use this function
- /// for performance optimizations where spurious `false` return values by this function do not
+ /// for performance optimizations where spurious `None` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
@@ -805,11 +823,14 @@ impl<T: ?Sized> *const T {
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
- pub const fn guaranteed_ne(self, other: *const T) -> bool
+ pub const fn guaranteed_ne(self, other: *const T) -> Option<bool>
where
T: Sized,
{
- intrinsics::ptr_guaranteed_ne(self, other)
+ match self.guaranteed_eq(other) {
+ None => None,
+ Some(eq) => Some(!eq),
+ }
}
/// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
@@ -1267,20 +1288,21 @@ impl<T: ?Sized> *const T {
/// Accessing adjacent `u8` as `u16`
///
/// ```
- /// # fn foo(n: usize) {
- /// # use std::mem::align_of;
+ /// use std::mem::align_of;
+ ///
/// # unsafe {
- /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
- /// let ptr = x.as_ptr().add(n) as *const u8;
+ /// let x = [5_u8, 6, 7, 8, 9];
+ /// let ptr = x.as_ptr();
/// let offset = ptr.align_offset(align_of::<u16>());
- /// if offset < x.len() - n - 1 {
- /// let u16_ptr = ptr.add(offset) as *const u16;
- /// assert_ne!(*u16_ptr, 500);
+ ///
+ /// if offset < x.len() - 1 {
+ /// let u16_ptr = ptr.add(offset).cast::<u16>();
+ /// assert!(*u16_ptr == u16::from_ne_bytes([5, 6]) || *u16_ptr == u16::from_ne_bytes([6, 7]));
/// } else {
/// // while the pointer can be aligned via `offset`, it would point
/// // outside the allocation
/// }
- /// # } }
+ /// # }
/// ```
#[stable(feature = "align_offset", since = "1.36.0")]
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
@@ -1336,11 +1358,8 @@ impl<T: ?Sized> *const T {
panic!("is_aligned_to: align is not a power-of-two");
}
- // SAFETY: `is_power_of_two()` will return `false` for zero.
- unsafe { core::intrinsics::assume(align != 0) };
-
// Cast is needed for `T: !Sized`
- self.cast::<u8>().addr() % align == 0
+ self.cast::<u8>().addr() & align - 1 == 0
}
}
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index cd5edee04..caa10f181 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -135,16 +135,16 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
}
#[repr(C)]
-pub(crate) union PtrRepr<T: ?Sized> {
- pub(crate) const_ptr: *const T,
- pub(crate) mut_ptr: *mut T,
- pub(crate) components: PtrComponents<T>,
+union PtrRepr<T: ?Sized> {
+ const_ptr: *const T,
+ mut_ptr: *mut T,
+ components: PtrComponents<T>,
}
#[repr(C)]
-pub(crate) struct PtrComponents<T: ?Sized> {
- pub(crate) data_address: *const (),
- pub(crate) metadata: <T as Pointee>::Metadata,
+struct PtrComponents<T: ?Sized> {
+ data_address: *const (),
+ metadata: <T as Pointee>::Metadata,
}
// Manual impl needed to avoid `T: Copy` bound.
@@ -180,7 +180,6 @@ pub struct DynMetadata<Dyn: ?Sized> {
phantom: crate::marker::PhantomData<Dyn>,
}
-#[cfg(not(bootstrap))]
extern "C" {
/// Opaque type for accessing vtables.
///
@@ -189,17 +188,6 @@ extern "C" {
type VTable;
}
-/// The common prefix of all vtables. It is followed by function pointers for trait methods.
-///
-/// Private implementation detail of `DynMetadata::size_of` etc.
-#[repr(C)]
-#[cfg(bootstrap)]
-struct VTable {
- drop_in_place: fn(*mut ()),
- size_of: usize,
- align_of: usize,
-}
-
impl<Dyn: ?Sized> DynMetadata<Dyn> {
/// Returns the size of the type associated with this vtable.
#[inline]
@@ -207,9 +195,6 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
// Note that "size stored in vtable" is *not* the same as "result of size_of_val_raw".
// Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the
// `Send` part!
- #[cfg(bootstrap)]
- return self.vtable_ptr.size_of;
- #[cfg(not(bootstrap))]
// SAFETY: DynMetadata always contains a valid vtable pointer
return unsafe {
crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ())
@@ -219,9 +204,6 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
/// Returns the alignment of the type associated with this vtable.
#[inline]
pub fn align_of(self) -> usize {
- #[cfg(bootstrap)]
- return self.vtable_ptr.align_of;
- #[cfg(not(bootstrap))]
// SAFETY: DynMetadata always contains a valid vtable pointer
return unsafe {
crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ())
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 40e28e636..565c38d22 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -90,7 +90,7 @@
//! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue
//! to conflate these notions). This would potentially make it possible to more efficiently
//! target platforms where pointers are larger than offsets, such as CHERI and maybe some
-//! segmented architecures.
+//! segmented architectures.
//!
//! ## Provenance
//!
@@ -172,7 +172,7 @@
//! a pointer to a usize is generally an operation which *only* extracts the address. It is
//! therefore *impossible* to construct a valid pointer from a usize because there is no way
//! to restore the address-space and provenance. In other words, pointer-integer-pointer
-//! roundtrips are not possible (in the sense that the resulting pointer is not dereferencable).
+//! roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable).
//!
//! The key insight to making this model *at all* viable is the [`with_addr`][] method:
//!
@@ -272,7 +272,7 @@
//!
//! * Create an invalid pointer from just an address (see [`ptr::invalid`][]). This can
//! be used for sentinel values like `null` *or* to represent a tagged pointer that will
-//! never be dereferencable. In general, it is always sound for an integer to pretend
+//! never be dereferenceable. In general, it is always sound for an integer to pretend
//! to be a pointer "for fun" as long as you don't use operations on it which require
//! it to be valid (offset, read, write, etc).
//!
@@ -377,6 +377,10 @@ use crate::intrinsics::{
use crate::mem::{self, MaybeUninit};
+mod alignment;
+#[unstable(feature = "ptr_alignment_type", issue = "102070")]
+pub use alignment::Alignment;
+
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(inline)]
pub use crate::intrinsics::copy_nonoverlapping;
@@ -390,7 +394,6 @@ pub use crate::intrinsics::copy;
pub use crate::intrinsics::write_bytes;
mod metadata;
-pub(crate) use metadata::PtrRepr;
#[unstable(feature = "ptr_metadata", issue = "81513")]
pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
@@ -578,12 +581,21 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
/// Convert an address back to a pointer, picking up a previously 'exposed' provenance.
///
/// This is equivalent to `addr as *const T`. The provenance of the returned pointer is that of *any*
-/// pointer that was previously passed to [`expose_addr`][pointer::expose_addr] or a `ptr as usize`
-/// cast. If there is no previously 'exposed' provenance that justifies the way this pointer will be
-/// used, the program has undefined behavior. Note that there is no algorithm that decides which
-/// provenance will be used. You can think of this as "guessing" the right provenance, and the guess
-/// will be "maximally in your favor", in the sense that if there is any way to avoid undefined
-/// behavior, then that is the guess that will be taken.
+/// pointer that was previously exposed by passing it to [`expose_addr`][pointer::expose_addr],
+/// or a `ptr as usize` cast. In addition, memory which is outside the control of the Rust abstract
+/// machine (MMIO registers, for example) is always considered to be exposed, so long as this memory
+/// is disjoint from memory that will be used by the abstract machine such as the stack, heap,
+/// and statics.
+///
+/// If there is no 'exposed' provenance that justifies the way this pointer will be used,
+/// the program has undefined behavior. In particular, the aliasing rules still apply: pointers
+/// and references that have been invalidated due to aliasing accesses cannot be used any more,
+/// even if they have been exposed!
+///
+/// Note that there is no algorithm that decides which provenance will be used. You can think of this
+/// as "guessing" the right provenance, and the guess will be "maximally in your favor", in the sense
+/// that if there is any way to avoid undefined behavior (while upholding all aliasing requirements),
+/// then that is the guess that will be taken.
///
/// On platforms with multiple address spaces, it is your responsibility to ensure that the
/// address makes sense in the address space that this pointer will be used with.
@@ -603,6 +615,7 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn from_exposed_addr<T>(addr: usize) -> *const T
where
T: Sized,
@@ -639,6 +652,7 @@ where
#[must_use]
#[inline]
#[unstable(feature = "strict_provenance", issue = "95228")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn from_exposed_addr_mut<T>(addr: usize) -> *mut T
where
T: Sized,
@@ -885,6 +899,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
// valid for writes and properly aligned.
unsafe {
assert_unsafe_precondition!(
+ "ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \
+ and the specified memory ranges do not overlap",
+ [T](x: *mut T, y: *mut T, count: usize) =>
is_aligned_and_not_null(x)
&& is_aligned_and_not_null(y)
&& is_nonoverlapping(x, y, count)
@@ -981,7 +998,10 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
// and cannot overlap `src` since `dst` must point to a distinct
// allocated object.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!(
+ "ptr::replace requires that the pointer argument is aligned and non-null",
+ [T](dst: *mut T) => is_aligned_and_not_null(dst)
+ );
mem::swap(&mut *dst, &mut src); // cannot overlap
}
src
@@ -1112,6 +1132,10 @@ pub const unsafe fn read<T>(src: *const T) -> T {
// Also, since we just wrote a valid value into `tmp`, it is guaranteed
// to be properly initialized.
unsafe {
+ assert_unsafe_precondition!(
+ "ptr::read requires that the pointer argument is aligned and non-null",
+ [T](src: *const T) => is_aligned_and_not_null(src)
+ );
copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
tmp.assume_init()
}
@@ -1305,6 +1329,10 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
// `dst` cannot overlap `src` because the caller has mutable access
// to `dst` while `src` is owned by this function.
unsafe {
+ assert_unsafe_precondition!(
+ "ptr::write requires that the pointer argument is aligned and non-null",
+ [T](dst: *mut T) => is_aligned_and_not_null(dst)
+ );
copy_nonoverlapping(&src as *const T, dst, 1);
intrinsics::forget(src);
}
@@ -1468,7 +1496,10 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
pub unsafe fn read_volatile<T>(src: *const T) -> T {
// SAFETY: the caller must uphold the safety contract for `volatile_load`.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(src));
+ assert_unsafe_precondition!(
+ "ptr::read_volatile requires that the pointer argument is aligned and non-null",
+ [T](src: *const T) => is_aligned_and_not_null(src)
+ );
intrinsics::volatile_load(src)
}
}
@@ -1539,7 +1570,10 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
// SAFETY: the caller must uphold the safety contract for `volatile_store`.
unsafe {
- assert_unsafe_precondition!(is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!(
+ "ptr::write_volatile requires that the pointer argument is aligned and non-null",
+ [T](dst: *mut T) => is_aligned_and_not_null(dst)
+ );
intrinsics::volatile_store(dst, src);
}
}
@@ -1726,6 +1760,12 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
/// by their address rather than comparing the values they point to
/// (which is what the `PartialEq for &T` implementation does).
///
+/// When comparing wide pointers, both the address and the metadata are tested for equality.
+/// However, note that comparing trait object pointers (`*const dyn Trait`) is unrealiable: pointers
+/// to values of the same underlying type can compare inequal (because vtables are duplicated in
+/// multiple codegen units), and pointers to values of *different* underlying type can compare equal
+/// (since identical vtables can be deduplicated within a codegen unit).
+///
/// # Examples
///
/// ```
@@ -1752,41 +1792,6 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
/// assert!(!std::ptr::eq(&a[..2], &a[..3]));
/// assert!(!std::ptr::eq(&a[0..2], &a[1..3]));
/// ```
-///
-/// Traits are also compared by their implementation:
-///
-/// ```
-/// #[repr(transparent)]
-/// struct Wrapper { member: i32 }
-///
-/// trait Trait {}
-/// impl Trait for Wrapper {}
-/// impl Trait for i32 {}
-///
-/// let wrapper = Wrapper { member: 10 };
-///
-/// // Pointers have equal addresses.
-/// assert!(std::ptr::eq(
-/// &wrapper as *const Wrapper as *const u8,
-/// &wrapper.member as *const i32 as *const u8
-/// ));
-///
-/// // Objects have equal addresses, but `Trait` has different implementations.
-/// assert!(!std::ptr::eq(
-/// &wrapper as &dyn Trait,
-/// &wrapper.member as &dyn Trait,
-/// ));
-/// assert!(!std::ptr::eq(
-/// &wrapper as &dyn Trait as *const dyn Trait,
-/// &wrapper.member as &dyn Trait as *const dyn Trait,
-/// ));
-///
-/// // Converting the reference to a `*const u8` compares by address.
-/// assert!(std::ptr::eq(
-/// &wrapper as &dyn Trait as *const dyn Trait as *const u8,
-/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8,
-/// ));
-/// ```
#[stable(feature = "ptr_eq", since = "1.17.0")]
#[inline]
pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
@@ -1834,7 +1839,7 @@ macro_rules! maybe_fnptr_doc {
$item
};
($a:ident @ #[$meta:meta] $item:item) => {
- #[cfg_attr(not(bootstrap), doc(fake_variadic))]
+ #[doc(fake_variadic)]
#[doc = "This trait is implemented for function pointers with up to twelve arguments."]
#[$meta]
$item
@@ -1854,9 +1859,16 @@ macro_rules! maybe_fnptr_doc {
// Impls for function pointers
macro_rules! fnptr_impls_safety_abi {
($FnTy: ty, $($Arg: ident),*) => {
+ fnptr_impls_safety_abi! { #[stable(feature = "fnptr_impls", since = "1.4.0")] $FnTy, $($Arg),* }
+ };
+ (@c_unwind $FnTy: ty, $($Arg: ident),*) => {
+ #[cfg(not(bootstrap))]
+ fnptr_impls_safety_abi! { #[unstable(feature = "c_unwind", issue = "74990")] $FnTy, $($Arg),* }
+ };
+ (#[$meta:meta] $FnTy: ty, $($Arg: ident),*) => {
maybe_fnptr_doc! {
$($Arg)* @
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ #[$meta]
impl<Ret, $($Arg),*> PartialEq for $FnTy {
#[inline]
fn eq(&self, other: &Self) -> bool {
@@ -1867,13 +1879,13 @@ macro_rules! fnptr_impls_safety_abi {
maybe_fnptr_doc! {
$($Arg)* @
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ #[$meta]
impl<Ret, $($Arg),*> Eq for $FnTy {}
}
maybe_fnptr_doc! {
$($Arg)* @
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ #[$meta]
impl<Ret, $($Arg),*> PartialOrd for $FnTy {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@@ -1884,7 +1896,7 @@ macro_rules! fnptr_impls_safety_abi {
maybe_fnptr_doc! {
$($Arg)* @
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ #[$meta]
impl<Ret, $($Arg),*> Ord for $FnTy {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
@@ -1895,7 +1907,7 @@ macro_rules! fnptr_impls_safety_abi {
maybe_fnptr_doc! {
$($Arg)* @
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ #[$meta]
impl<Ret, $($Arg),*> hash::Hash for $FnTy {
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
state.write_usize(*self as usize)
@@ -1905,7 +1917,7 @@ macro_rules! fnptr_impls_safety_abi {
maybe_fnptr_doc! {
$($Arg)* @
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ #[$meta]
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(*self as usize, f)
@@ -1915,7 +1927,7 @@ macro_rules! fnptr_impls_safety_abi {
maybe_fnptr_doc! {
$($Arg)* @
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ #[$meta]
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(*self as usize, f)
@@ -1930,16 +1942,22 @@ macro_rules! fnptr_impls_args {
fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
fnptr_impls_safety_abi! { extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
fnptr_impls_safety_abi! { extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
+ fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
+ fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
+ fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
+ fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
};
() => {
// No variadic functions with 0 parameters
fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, }
fnptr_impls_safety_abi! { extern "C" fn() -> Ret, }
+ fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn() -> Ret, }
fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, }
fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, }
+ fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn() -> Ret, }
};
}
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index fc3dd2a9b..6764002bc 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -35,7 +35,10 @@ impl<T: ?Sized> *mut T {
pub const fn is_null(self) -> bool {
// Compare via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
- (self as *mut u8).guaranteed_eq(null_mut())
+ match (self as *mut u8).guaranteed_eq(null_mut()) {
+ None => false,
+ Some(res) => res,
+ }
}
/// Casts to a pointer of another type.
@@ -77,10 +80,14 @@ impl<T: ?Sized> *mut T {
#[unstable(feature = "set_ptr_value", issue = "75091")]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[inline]
- pub fn with_metadata_of<U>(self, mut val: *mut U) -> *mut U
+ pub fn with_metadata_of<U>(self, val: *const U) -> *mut U
where
U: ?Sized,
{
+ // Prepare in the type system that we will replace the pointer value with a mutable
+ // pointer, taking the mutable provenance from the `self` pointer.
+ let mut val = val as *mut U;
+ // Pointer to the pointer value within the value.
let target = &mut val as *mut *mut U as *mut *mut u8;
// SAFETY: In case of a thin pointer, this operations is identical
// to a simple assignment. In case of a fat pointer, with the current
@@ -100,8 +107,8 @@ impl<T: ?Sized> *mut T {
/// coercion.
///
/// [`cast_mut`]: #method.cast_mut
- #[unstable(feature = "ptr_const_cast", issue = "92675")]
- #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+ #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+ #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
pub const fn cast_const(self) -> *const T {
self as _
}
@@ -160,7 +167,7 @@ impl<T: ?Sized> *mut T {
/// This is similar to `self as usize`, which semantically discards *provenance* and
/// *address-space* information. However, unlike `self as usize`, casting the returned address
/// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To
- /// properly restore the lost information and obtain a dereferencable pointer, use
+ /// properly restore the lost information and obtain a dereferenceable pointer, use
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
///
/// If using those APIs is not possible because there is no way to preserve a pointer with the
@@ -255,7 +262,7 @@ impl<T: ?Sized> *mut T {
let offset = dest_addr.wrapping_sub(self_addr);
// This is the canonical desugarring of this operation
- self.cast::<u8>().wrapping_offset(offset).cast::<T>()
+ self.wrapping_byte_offset(offset)
}
/// Creates a new pointer by mapping `self`'s address to a new one.
@@ -575,6 +582,20 @@ impl<T: ?Sized> *mut T {
)
}
+ /// Masks out bits of the pointer according to a mask.
+ ///
+ /// This is convenience for `ptr.map_addr(|a| a & mask)`.
+ ///
+ /// For non-`Sized` pointees this operation changes only the data pointer,
+ /// leaving the metadata untouched.
+ #[unstable(feature = "ptr_mask", issue = "98290")]
+ #[must_use = "returns a new pointer rather than modifying its argument"]
+ #[inline(always)]
+ pub fn mask(self, mask: usize) -> *mut T {
+ let this = intrinsics::ptr_mask(self.cast::<()>(), mask) as *mut ();
+ from_raw_parts_mut::<T>(this, metadata(self))
+ }
+
/// Returns `None` if the pointer is null, or else returns a unique reference to
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_mut`]
/// must be used instead.
@@ -682,20 +703,16 @@ impl<T: ?Sized> *mut T {
/// Returns whether two pointers are guaranteed to be equal.
///
- /// At runtime this function behaves like `self == other`.
+ /// At runtime this function behaves like `Some(self == other)`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine equality of two pointers, so this function may
- /// spuriously return `false` for pointers that later actually turn out to be equal.
- /// But when it returns `true`, the pointers are guaranteed to be equal.
+ /// spuriously return `None` for pointers that later actually turn out to have its equality known.
+ /// But when it returns `Some`, the pointers' equality is guaranteed to be known.
///
- /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
- /// comparisons for which both functions return `false`.
- ///
- /// [`guaranteed_ne`]: #method.guaranteed_ne
- ///
- /// The return value may change depending on the compiler version and unsafe code might not
+ /// The return value may change from `Some` to `None` and vice versa depending on the compiler
+ /// version and unsafe code must not
/// rely on the result of this function for soundness. It is suggested to only use this function
- /// for performance optimizations where spurious `false` return values by this function do not
+ /// for performance optimizations where spurious `None` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
@@ -704,29 +721,25 @@ impl<T: ?Sized> *mut T {
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
- pub const fn guaranteed_eq(self, other: *mut T) -> bool
+ pub const fn guaranteed_eq(self, other: *mut T) -> Option<bool>
where
T: Sized,
{
- intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
+ (self as *const T).guaranteed_eq(other as _)
}
- /// Returns whether two pointers are guaranteed to be unequal.
+ /// Returns whether two pointers are guaranteed to be inequal.
///
- /// At runtime this function behaves like `self != other`.
+ /// At runtime this function behaves like `Some(self != other)`.
/// However, in some contexts (e.g., compile-time evaluation),
- /// it is not always possible to determine the inequality of two pointers, so this function may
- /// spuriously return `false` for pointers that later actually turn out to be unequal.
- /// But when it returns `true`, the pointers are guaranteed to be unequal.
- ///
- /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
- /// comparisons for which both functions return `false`.
+ /// it is not always possible to determine inequality of two pointers, so this function may
+ /// spuriously return `None` for pointers that later actually turn out to have its inequality known.
+ /// But when it returns `Some`, the pointers' inequality is guaranteed to be known.
///
- /// [`guaranteed_eq`]: #method.guaranteed_eq
- ///
- /// The return value may change depending on the compiler version and unsafe code might not
+ /// The return value may change from `Some` to `None` and vice versa depending on the compiler
+ /// version and unsafe code must not
/// rely on the result of this function for soundness. It is suggested to only use this function
- /// for performance optimizations where spurious `false` return values by this function do not
+ /// for performance optimizations where spurious `None` return values by this function do not
/// affect the outcome, but just the performance.
/// The consequences of using this method to make runtime and compile-time code behave
/// differently have not been explored. This method should not be used to introduce such
@@ -735,11 +748,11 @@ impl<T: ?Sized> *mut T {
#[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
#[inline]
- pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
+ pub const fn guaranteed_ne(self, other: *mut T) -> Option<bool>
where
T: Sized,
{
- intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
+ (self as *const T).guaranteed_ne(other as _)
}
/// Calculates the distance between two pointers. The returned value is in
@@ -824,7 +837,7 @@ impl<T: ?Sized> *mut T {
/// }
/// ```
#[stable(feature = "ptr_offset_from", since = "1.47.0")]
- #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
+ #[rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0")]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn offset_from(self, origin: *const T) -> isize
@@ -858,7 +871,7 @@ impl<T: ?Sized> *mut T {
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///
/// This computes the same value that [`offset_from`](#method.offset_from)
- /// would compute, but with the added precondition that that the offset is
+ /// would compute, but with the added precondition that the offset is
/// guaranteed to be non-negative. This method is equivalent to
/// `usize::from(self.offset_from(origin)).unwrap_unchecked()`,
/// but it provides slightly more information to the optimizer, which can
@@ -1545,20 +1558,23 @@ impl<T: ?Sized> *mut T {
/// Accessing adjacent `u8` as `u16`
///
/// ```
- /// # fn foo(n: usize) {
- /// # use std::mem::align_of;
+ /// use std::mem::align_of;
+ ///
/// # unsafe {
- /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
- /// let ptr = x.as_ptr().add(n) as *const u8;
+ /// let mut x = [5_u8, 6, 7, 8, 9];
+ /// let ptr = x.as_mut_ptr();
/// let offset = ptr.align_offset(align_of::<u16>());
- /// if offset < x.len() - n - 1 {
- /// let u16_ptr = ptr.add(offset) as *const u16;
- /// assert_ne!(*u16_ptr, 500);
+ ///
+ /// if offset < x.len() - 1 {
+ /// let u16_ptr = ptr.add(offset).cast::<u16>();
+ /// *u16_ptr = 0;
+ ///
+ /// assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]);
/// } else {
/// // while the pointer can be aligned via `offset`, it would point
/// // outside the allocation
/// }
- /// # } }
+ /// # }
/// ```
#[stable(feature = "align_offset", since = "1.36.0")]
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
@@ -1614,11 +1630,8 @@ impl<T: ?Sized> *mut T {
panic!("is_aligned_to: align is not a power-of-two");
}
- // SAFETY: `is_power_of_two()` will return `false` for zero.
- unsafe { core::intrinsics::assume(align != 0) };
-
// Cast is needed for `T: !Sized`
- self.cast::<u8>().addr() % align == 0
+ self.cast::<u8>().addr() & align - 1 == 0
}
}
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index f3ef094cb..c18264d13 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -2,6 +2,7 @@ use crate::cmp::Ordering;
use crate::convert::From;
use crate::fmt;
use crate::hash;
+use crate::intrinsics::assert_unsafe_precondition;
use crate::marker::Unsize;
use crate::mem::{self, MaybeUninit};
use crate::num::NonZeroUsize;
@@ -195,7 +196,10 @@ impl<T: ?Sized> NonNull<T> {
#[inline]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
// SAFETY: the caller must guarantee that `ptr` is non-null.
- unsafe { NonNull { pointer: ptr as _ } }
+ unsafe {
+ assert_unsafe_precondition!("NonNull::new_unchecked requires that the pointer is non-null", [T: ?Sized](ptr: *mut T) => !ptr.is_null());
+ NonNull { pointer: ptr as _ }
+ }
}
/// Creates a new `NonNull` if `ptr` is non-null.
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 45b052c82..3f33c5fd6 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -548,22 +548,25 @@ impl<T, E> Result<T, E> {
/// # Examples
///
/// ```
- /// #![feature(is_some_with)]
+ /// #![feature(is_some_and)]
///
/// let x: Result<u32, &str> = Ok(2);
- /// assert_eq!(x.is_ok_and(|&x| x > 1), true);
+ /// assert_eq!(x.is_ok_and(|x| x > 1), true);
///
/// let x: Result<u32, &str> = Ok(0);
- /// assert_eq!(x.is_ok_and(|&x| x > 1), false);
+ /// assert_eq!(x.is_ok_and(|x| x > 1), false);
///
/// let x: Result<u32, &str> = Err("hey");
- /// assert_eq!(x.is_ok_and(|&x| x > 1), false);
+ /// assert_eq!(x.is_ok_and(|x| x > 1), false);
/// ```
#[must_use]
#[inline]
- #[unstable(feature = "is_some_with", issue = "93050")]
- pub fn is_ok_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
- matches!(self, Ok(x) if f(x))
+ #[unstable(feature = "is_some_and", issue = "93050")]
+ pub fn is_ok_and(self, f: impl FnOnce(T) -> bool) -> bool {
+ match self {
+ Err(_) => false,
+ Ok(x) => f(x),
+ }
}
/// Returns `true` if the result is [`Err`].
@@ -592,7 +595,7 @@ impl<T, E> Result<T, E> {
/// # Examples
///
/// ```
- /// #![feature(is_some_with)]
+ /// #![feature(is_some_and)]
/// use std::io::{Error, ErrorKind};
///
/// let x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, "!"));
@@ -606,9 +609,12 @@ impl<T, E> Result<T, E> {
/// ```
#[must_use]
#[inline]
- #[unstable(feature = "is_some_with", issue = "93050")]
- pub fn is_err_and(&self, f: impl FnOnce(&E) -> bool) -> bool {
- matches!(self, Err(x) if f(x))
+ #[unstable(feature = "is_some_and", issue = "93050")]
+ pub fn is_err_and(self, f: impl FnOnce(E) -> bool) -> bool {
+ match self {
+ Ok(_) => false,
+ Err(e) => f(e),
+ }
}
/////////////////////////////////////////////////////////////////////////
@@ -1285,6 +1291,11 @@ impl<T, E> Result<T, E> {
/// Returns `res` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`.
///
+ /// Arguments passed to `and` are eagerly evaluated; if you are passing the
+ /// result of a function call, it is recommended to use [`and_then`], which is
+ /// lazily evaluated.
+ ///
+ /// [`and_then`]: Result::and_then
///
/// # Examples
///
@@ -1771,40 +1782,6 @@ impl<T, E> Result<Result<T, E>, E> {
}
}
-impl<T> Result<T, T> {
- /// Returns the [`Ok`] value if `self` is `Ok`, and the [`Err`] value if
- /// `self` is `Err`.
- ///
- /// In other words, this function returns the value (the `T`) of a
- /// `Result<T, T>`, regardless of whether or not that result is `Ok` or
- /// `Err`.
- ///
- /// This can be useful in conjunction with APIs such as
- /// [`Atomic*::compare_exchange`], or [`slice::binary_search`], but only in
- /// cases where you don't care if the result was `Ok` or not.
- ///
- /// [`Atomic*::compare_exchange`]: crate::sync::atomic::AtomicBool::compare_exchange
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(result_into_ok_or_err)]
- /// let ok: Result<u32, u32> = Ok(3);
- /// let err: Result<u32, u32> = Err(4);
- ///
- /// assert_eq!(ok.into_ok_or_err(), 3);
- /// assert_eq!(err.into_ok_or_err(), 4);
- /// ```
- #[inline]
- #[unstable(feature = "result_into_ok_or_err", reason = "newly added", issue = "82223")]
- pub const fn into_ok_or_err(self) -> T {
- match self {
- Ok(v) => v,
- Err(v) => v,
- }
- }
-}
-
// This is a separate function to reduce the code size of the methods
#[cfg(not(feature = "panic_immediate_abort"))]
#[inline(never)]
@@ -2095,9 +2072,6 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
/// so the final value of `shared` is 6 (= `3 + 2 + 1`), not 16.
#[inline]
fn from_iter<I: IntoIterator<Item = Result<A, E>>>(iter: I) -> Result<V, E> {
- // FIXME(#11084): This could be replaced with Iterator::scan when this
- // performance bug is closed.
-
iter::try_process(iter.into_iter(), |i| i.collect())
}
}
@@ -2145,6 +2119,7 @@ impl<T, E, F: From<E>> ops::FromResidual<ops::Yeet<E>> for Result<T, F> {
}
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
-impl<T, E> ops::Residual<T> for Result<convert::Infallible, E> {
+#[rustc_const_unstable(feature = "const_try", issue = "74935")]
+impl<T, E> const ops::Residual<T> for Result<convert::Infallible, E> {
type TryType = Result<T, E>;
}
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index 63715a6b8..5e5399acc 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -215,8 +215,6 @@ impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> {
}
}
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
-impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {}
-#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> iter::FusedIterator for EscapeAscii<'a> {}
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
impl<'a> fmt::Display for EscapeAscii<'a> {
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index fd7ecf3da..6d2f7330d 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -48,10 +48,12 @@ const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
}
// FIXME const-hack
+#[track_caller]
fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! {
panic!("range start index {index} out of range for slice of length {len}");
}
+#[track_caller]
const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
panic!("slice start index is out of range for slice");
}
@@ -69,10 +71,12 @@ const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
}
// FIXME const-hack
+#[track_caller]
fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! {
panic!("range end index {index} out of range for slice of length {len}");
}
+#[track_caller]
const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
panic!("slice end index is out of range for slice");
}
@@ -88,10 +92,12 @@ const fn slice_index_order_fail(index: usize, end: usize) -> ! {
}
// FIXME const-hack
+#[track_caller]
fn slice_index_order_fail_rt(index: usize, end: usize) -> ! {
panic!("slice index starts at {index} but ends at {end}");
}
+#[track_caller]
const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! {
panic!("slice index start is larger than end");
}
@@ -133,6 +139,8 @@ mod private_slice_index {
impl Sealed for ops::RangeToInclusive<usize> {}
#[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")]
impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {}
+
+ impl Sealed for ops::IndexRange {}
}
/// A helper trait used for indexing operations.
@@ -152,6 +160,7 @@ mod private_slice_index {
message = "the type `{T}` cannot be indexed by `{Self}`",
label = "slice indices are of type `usize` or ranges of `usize`"
)]
+#[const_trait]
pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
/// The output type returned by methods.
#[stable(feature = "slice_get_slice", since = "1.28.0")]
@@ -217,21 +226,29 @@ unsafe impl<T> const SliceIndex<[T]> for usize {
#[inline]
unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
+ let this = self;
// SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
// so the call to `add` is safe.
unsafe {
- assert_unsafe_precondition!(self < slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked requires that the index is within the slice",
+ [T](this: usize, slice: *const [T]) => this < slice.len()
+ );
slice.as_ptr().add(self)
}
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
+ let this = self;
// SAFETY: see comments for `get_unchecked` above.
unsafe {
- assert_unsafe_precondition!(self < slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked_mut requires that the index is within the slice",
+ [T](this: usize, slice: *mut [T]) => this < slice.len()
+ );
slice.as_mut_ptr().add(self)
}
}
@@ -249,6 +266,83 @@ unsafe impl<T> const SliceIndex<[T]> for usize {
}
}
+/// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here
+/// than there are for a general `Range<usize>` (which might be `100..3`).
+#[rustc_const_unstable(feature = "const_index_range_slice_index", issue = "none")]
+unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
+ type Output = [T];
+
+ #[inline]
+ fn get(self, slice: &[T]) -> Option<&[T]> {
+ if self.end() <= slice.len() {
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { Some(&*self.get_unchecked(slice)) }
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+ if self.end() <= slice.len() {
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ let end = self.end();
+ // SAFETY: the caller guarantees that `slice` is not dangling, so it
+ // cannot be longer than `isize::MAX`. They also guarantee that
+ // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+ // so the call to `add` is safe.
+
+ unsafe {
+ assert_unsafe_precondition!(
+ "slice::get_unchecked requires that the index is within the slice",
+ [T](end: usize, slice: *const [T]) => end <= slice.len()
+ );
+ ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len())
+ }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+ let end = self.end();
+ // SAFETY: see comments for `get_unchecked` above.
+ unsafe {
+ assert_unsafe_precondition!(
+ "slice::get_unchecked_mut requires that the index is within the slice",
+ [T](end: usize, slice: *mut [T]) => end <= slice.len()
+ );
+ ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len())
+ }
+ }
+
+ #[inline]
+ fn index(self, slice: &[T]) -> &[T] {
+ if self.end() <= slice.len() {
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { &*self.get_unchecked(slice) }
+ } else {
+ slice_end_index_len_fail(self.end(), slice.len())
+ }
+ }
+
+ #[inline]
+ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+ if self.end() <= slice.len() {
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { &mut *self.get_unchecked_mut(slice) }
+ } else {
+ slice_end_index_len_fail(self.end(), slice.len())
+ }
+ }
+}
+
#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
@@ -276,22 +370,32 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
#[inline]
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ let this = ops::Range { start: self.start, end: self.end };
// SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
// so the call to `add` is safe.
unsafe {
- assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked requires that the range is within the slice",
+ [T](this: ops::Range<usize>, slice: *const [T]) =>
+ this.end >= this.start && this.end <= slice.len()
+ );
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start)
}
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+ let this = ops::Range { start: self.start, end: self.end };
// SAFETY: see comments for `get_unchecked` above.
unsafe {
- assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked_mut requires that the range is within the slice",
+ [T](this: ops::Range<usize>, slice: *mut [T]) =>
+ this.end >= this.start && this.end <= slice.len()
+ );
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
}
}
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index f1e659309..8a8962828 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -9,7 +9,7 @@ use crate::fmt;
use crate::intrinsics::{assume, exact_div, unchecked_sub};
use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
use crate::marker::{PhantomData, Send, Sized, Sync};
-use crate::mem;
+use crate::mem::{self, SizedTypeProperties};
use crate::num::NonZeroUsize;
use crate::ptr::NonNull;
@@ -91,11 +91,8 @@ impl<'a, T> Iter<'a, T> {
unsafe {
assume(!ptr.is_null());
- let end = if mem::size_of::<T>() == 0 {
- (ptr as *const u8).wrapping_add(slice.len()) as *const T
- } else {
- ptr.add(slice.len())
- };
+ let end =
+ if T::IS_ZST { ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) };
Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData }
}
@@ -127,6 +124,7 @@ impl<'a, T> Iter<'a, T> {
/// ```
#[must_use]
#[stable(feature = "iter_to_slice", since = "1.4.0")]
+ #[inline]
pub fn as_slice(&self) -> &'a [T] {
self.make_slice()
}
@@ -146,6 +144,7 @@ iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Clone for Iter<'_, T> {
+ #[inline]
fn clone(&self) -> Self {
Iter { ptr: self.ptr, end: self.end, _marker: self._marker }
}
@@ -153,6 +152,7 @@ impl<T> Clone for Iter<'_, T> {
#[stable(feature = "slice_iter_as_ref", since = "1.13.0")]
impl<T> AsRef<[T]> for Iter<'_, T> {
+ #[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
@@ -227,11 +227,8 @@ impl<'a, T> IterMut<'a, T> {
unsafe {
assume(!ptr.is_null());
- let end = if mem::size_of::<T>() == 0 {
- (ptr as *mut u8).wrapping_add(slice.len()) as *mut T
- } else {
- ptr.add(slice.len())
- };
+ let end =
+ if T::IS_ZST { ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) };
Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData }
}
@@ -303,6 +300,7 @@ impl<'a, T> IterMut<'a, T> {
/// ```
#[must_use]
#[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")]
+ #[inline]
pub fn as_slice(&self) -> &[T] {
self.make_slice()
}
@@ -351,6 +349,7 @@ impl<'a, T> IterMut<'a, T> {
#[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")]
impl<T> AsRef<[T]> for IterMut<'_, T> {
+ #[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
@@ -2754,10 +2753,10 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
None => 0,
};
// SAFETY: This type ensures that self.v is a valid pointer with a correct len.
- // Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
+ // Therefore the bounds check in split_at_mut guarantees the split point is inbounds.
let (head, tail) = unsafe { self.v.split_at_mut(start) };
// SAFETY: This type ensures that self.v is a valid pointer with a correct len.
- // Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
+ // Therefore the bounds check in split_at_mut guarantees the split point is inbounds.
let (nth, _) = unsafe { tail.split_at_mut(end - start) };
self.v = head;
// SAFETY: Nothing else points to or will point to the contents of this slice.
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index c05242222..ce51d48e3 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -64,7 +64,7 @@ macro_rules! iterator {
// backwards by `n`. `n` must not exceed `self.len()`.
macro_rules! zst_shrink {
($self: ident, $n: ident) => {
- $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T;
+ $self.end = $self.end.wrapping_byte_sub($n);
}
}
@@ -82,7 +82,7 @@ macro_rules! iterator {
// returning the old start.
// Unsafe because the offset must not exceed `self.len()`.
#[inline(always)]
- unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
+ unsafe fn post_inc_start(&mut self, offset: usize) -> * $raw_mut T {
if mem::size_of::<T>() == 0 {
zst_shrink!(self, offset);
self.ptr.as_ptr()
@@ -90,7 +90,7 @@ macro_rules! iterator {
let old = self.ptr.as_ptr();
// SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
// so this new pointer is inside `self` and thus guaranteed to be non-null.
- self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) };
+ self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) };
old
}
}
@@ -99,15 +99,15 @@ macro_rules! iterator {
// returning the new end.
// Unsafe because the offset must not exceed `self.len()`.
#[inline(always)]
- unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
- if mem::size_of::<T>() == 0 {
+ unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T {
+ if T::IS_ZST {
zst_shrink!(self, offset);
self.ptr.as_ptr()
} else {
// SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
// which is guaranteed to not overflow an `isize`. Also, the resulting pointer
// is in bounds of `slice`, which fulfills the other requirements for `offset`.
- self.end = unsafe { self.end.offset(-offset) };
+ self.end = unsafe { self.end.sub(offset) };
self.end
}
}
@@ -140,7 +140,7 @@ macro_rules! iterator {
// since we check if the iterator is empty first.
unsafe {
assume(!self.ptr.as_ptr().is_null());
- if mem::size_of::<T>() != 0 {
+ if !<T>::IS_ZST {
assume(!self.end.is_null());
}
if is_empty!(self) {
@@ -166,7 +166,7 @@ macro_rules! iterator {
fn nth(&mut self, n: usize) -> Option<$elem> {
if n >= len!(self) {
// This iterator is now empty.
- if mem::size_of::<T>() == 0 {
+ if T::IS_ZST {
// We have to do it this way as `ptr` may never be 0, but `end`
// could be (due to wrapping).
self.end = self.ptr.as_ptr();
@@ -180,7 +180,7 @@ macro_rules! iterator {
}
// SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
unsafe {
- self.post_inc_start(n as isize);
+ self.post_inc_start(n);
Some(next_unchecked!(self))
}
}
@@ -189,7 +189,7 @@ macro_rules! iterator {
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let advance = cmp::min(len!(self), n);
// SAFETY: By construction, `advance` does not exceed `self.len()`.
- unsafe { self.post_inc_start(advance as isize) };
+ unsafe { self.post_inc_start(advance) };
if advance == n { Ok(()) } else { Err(advance) }
}
@@ -355,7 +355,7 @@ macro_rules! iterator {
// empty first.
unsafe {
assume(!self.ptr.as_ptr().is_null());
- if mem::size_of::<T>() != 0 {
+ if !<T>::IS_ZST {
assume(!self.end.is_null());
}
if is_empty!(self) {
@@ -375,7 +375,7 @@ macro_rules! iterator {
}
// SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
unsafe {
- self.pre_dec_end(n as isize);
+ self.pre_dec_end(n);
Some(next_back_unchecked!(self))
}
}
@@ -384,7 +384,7 @@ macro_rules! iterator {
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
let advance = cmp::min(len!(self), n);
// SAFETY: By construction, `advance` does not exceed `self.len()`.
- unsafe { self.pre_dec_end(advance as isize) };
+ unsafe { self.pre_dec_end(advance) };
if advance == n { Ok(()) } else { Err(advance) }
}
}
diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs
index dffeaf6a8..c848c2e18 100644
--- a/library/core/src/slice/memchr.rs
+++ b/library/core/src/slice/memchr.rs
@@ -16,35 +16,51 @@ const USIZE_BYTES: usize = mem::size_of::<usize>();
/// bytes where the borrow propagated all the way to the most significant
/// bit."
#[inline]
-fn contains_zero_byte(x: usize) -> bool {
+const fn contains_zero_byte(x: usize) -> bool {
x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
}
#[cfg(target_pointer_width = "16")]
#[inline]
-fn repeat_byte(b: u8) -> usize {
+const fn repeat_byte(b: u8) -> usize {
(b as usize) << 8 | b as usize
}
#[cfg(not(target_pointer_width = "16"))]
#[inline]
-fn repeat_byte(b: u8) -> usize {
+const fn repeat_byte(b: u8) -> usize {
(b as usize) * (usize::MAX / 255)
}
/// Returns the first index matching the byte `x` in `text`.
#[must_use]
#[inline]
-pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
- // Fast path for small slices
+pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
+ // Fast path for small slices.
if text.len() < 2 * USIZE_BYTES {
- return text.iter().position(|elt| *elt == x);
+ return memchr_naive(x, text);
}
- memchr_general_case(x, text)
+ memchr_aligned(x, text)
}
-fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
+#[inline]
+const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
+ let mut i = 0;
+
+ // FIXME(const-hack): Replace with `text.iter().pos(|c| *c == x)`.
+ while i < text.len() {
+ if text[i] == x {
+ return Some(i);
+ }
+
+ i += 1;
+ }
+
+ None
+}
+
+const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
// Scan for a single byte value by reading two `usize` words at a time.
//
// Split `text` in three parts
@@ -59,7 +75,7 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
if offset > 0 {
offset = cmp::min(offset, len);
- if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
+ if let Some(index) = memchr_naive(x, &text[..offset]) {
return Some(index);
}
}
@@ -84,7 +100,8 @@ fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
}
// Find the byte after the point the body loop stopped.
- text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i)
+ // FIXME(const-hack): Use `?` instead.
+ if let Some(i) = memchr_naive(x, &text[offset..]) { Some(offset + i) } else { None }
}
/// Returns the last index matching the byte `x` in `text`.
@@ -124,8 +141,8 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
// SAFETY: offset starts at len - suffix.len(), as long as it is greater than
// min_aligned_offset (prefix.len()) the remaining distance is at least 2 * chunk_bytes.
unsafe {
- let u = *(ptr.offset(offset as isize - 2 * chunk_bytes as isize) as *const Chunk);
- let v = *(ptr.offset(offset as isize - chunk_bytes as isize) as *const Chunk);
+ let u = *(ptr.add(offset - 2 * chunk_bytes) as *const Chunk);
+ let v = *(ptr.add(offset - chunk_bytes) as *const Chunk);
// Break if there is a matching byte.
let zu = contains_zero_byte(u ^ repeated_x);
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index e6ca6ef82..4f1bb1734 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -9,7 +9,7 @@
use crate::cmp::Ordering::{self, Greater, Less};
use crate::intrinsics::{assert_unsafe_precondition, exact_div};
use crate::marker::Copy;
-use crate::mem;
+use crate::mem::{self, SizedTypeProperties};
use crate::num::NonZeroUsize;
use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds};
use crate::option::Option;
@@ -123,18 +123,11 @@ impl<T> [T] {
#[lang = "slice_len_fn"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")]
+ #[rustc_allow_const_fn_unstable(ptr_metadata)]
#[inline]
#[must_use]
- // SAFETY: const sound because we transmute out the length field as a usize (which it must be)
pub const fn len(&self) -> usize {
- // FIXME: Replace with `crate::ptr::metadata(self)` when that is const-stable.
- // As of this writing this causes a "Const-stable functions can only call other
- // const-stable functions" error.
-
- // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
- // and PtrComponents<T> have the same memory layouts. Only std can make this
- // guarantee.
- unsafe { crate::ptr::PtrRepr { const_ptr: self }.components.metadata }
+ ptr::metadata(self)
}
/// Returns `true` if the slice has a length of 0.
@@ -656,10 +649,14 @@ impl<T> [T] {
#[unstable(feature = "slice_swap_unchecked", issue = "88539")]
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
- let ptr = self.as_mut_ptr();
+ let this = self;
+ let ptr = this.as_mut_ptr();
// SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()`
unsafe {
- assert_unsafe_precondition!(a < self.len() && b < self.len());
+ assert_unsafe_precondition!(
+ "slice::swap_unchecked requires that the indices are within the slice",
+ [T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len()
+ );
ptr::swap(ptr.add(a), ptr.add(b));
}
}
@@ -674,8 +671,9 @@ impl<T> [T] {
/// assert!(v == [3, 2, 1]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_reverse", issue = "100784")]
#[inline]
- pub fn reverse(&mut self) {
+ pub const fn reverse(&mut self) {
let half_len = self.len() / 2;
let Range { start, end } = self.as_mut_ptr_range();
@@ -698,9 +696,9 @@ impl<T> [T] {
revswap(front_half, back_half, half_len);
#[inline]
- fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) {
- debug_assert_eq!(a.len(), n);
- debug_assert_eq!(b.len(), n);
+ const fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) {
+ debug_assert!(a.len() == n);
+ debug_assert!(b.len() == n);
// Because this function is first compiled in isolation,
// this check tells LLVM that the indexing below is
@@ -708,8 +706,10 @@ impl<T> [T] {
// lengths of the slices are known -- it's removed.
let (a, b) = (&mut a[..n], &mut b[..n]);
- for i in 0..n {
+ let mut i = 0;
+ while i < n {
mem::swap(&mut a[i], &mut b[n - 1 - i]);
+ i += 1;
}
}
}
@@ -969,9 +969,13 @@ impl<T> [T] {
#[inline]
#[must_use]
pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
+ let this = self;
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
let new_len = unsafe {
- assert_unsafe_precondition!(N != 0 && self.len() % N == 0);
+ assert_unsafe_precondition!(
+ "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
+ [T](this: &[T], N: usize) => N != 0 && this.len() % N == 0
+ );
exact_div(self.len(), N)
};
// SAFETY: We cast a slice of `new_len * N` elements into
@@ -1108,10 +1112,14 @@ impl<T> [T] {
#[inline]
#[must_use]
pub unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
+ let this = &*self;
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
let new_len = unsafe {
- assert_unsafe_precondition!(N != 0 && self.len() % N == 0);
- exact_div(self.len(), N)
+ assert_unsafe_precondition!(
+ "slice::as_chunks_unchecked_mut requires `N != 0` and the slice to split exactly into `N`-element chunks",
+ [T](this: &[T], N: usize) => N != 0 && this.len() % N == 0
+ );
+ exact_div(this.len(), N)
};
// SAFETY: We cast a slice of `new_len * N` elements into
// a slice of `new_len` many `N` elements chunks.
@@ -1538,13 +1546,14 @@ impl<T> [T] {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "101158")]
#[inline]
#[track_caller]
#[must_use]
- pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
+ pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) {
assert!(mid <= self.len());
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
- // fulfills the requirements of `from_raw_parts_mut`.
+ // fulfills the requirements of `split_at_unchecked`.
unsafe { self.split_at_unchecked(mid) }
}
@@ -1573,7 +1582,8 @@ impl<T> [T] {
#[inline]
#[track_caller]
#[must_use]
- pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
+ #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
+ pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
assert!(mid <= self.len());
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
// fulfills the requirements of `from_raw_parts_mut`.
@@ -1623,11 +1633,19 @@ impl<T> [T] {
/// }
/// ```
#[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")]
+ #[rustc_const_unstable(feature = "slice_split_at_unchecked", issue = "76014")]
#[inline]
#[must_use]
- pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) {
+ pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) {
+ // HACK: the const function `from_raw_parts` is used to make this
+ // function const; previously the implementation used
+ // `(self.get_unchecked(..mid), self.get_unchecked(mid..))`
+
+ let len = self.len();
+ let ptr = self.as_ptr();
+
// SAFETY: Caller has to check that `0 <= mid <= self.len()`
- unsafe { (self.get_unchecked(..mid), self.get_unchecked(mid..)) }
+ unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) }
}
/// Divides one mutable slice into two at an index, without doing bounds checking.
@@ -1664,9 +1682,10 @@ impl<T> [T] {
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
/// ```
#[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")]
+ #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
#[inline]
#[must_use]
- pub unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
+ pub const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
let len = self.len();
let ptr = self.as_mut_ptr();
@@ -1675,7 +1694,10 @@ impl<T> [T] {
// `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference
// is fine.
unsafe {
- assert_unsafe_precondition!(mid <= len);
+ assert_unsafe_precondition!(
+ "slice::split_at_mut_unchecked requires the index to be within the slice",
+ (mid: usize, len: usize) => mid <= len
+ );
(from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid))
}
}
@@ -2059,7 +2081,7 @@ impl<T> [T] {
SplitN::new(self.split(pred), n)
}
- /// Returns an iterator over subslices separated by elements that match
+ /// Returns an iterator over mutable subslices separated by elements that match
/// `pred`, limited to returning at most `n` items. The matched element is
/// not contained in the subslices.
///
@@ -2309,7 +2331,7 @@ impl<T> [T] {
}
/// Binary searches this slice for a given element.
- /// This behaves similary to [`contains`] if this slice is sorted.
+ /// This behaves similarly to [`contains`] if this slice is sorted.
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
@@ -2342,6 +2364,28 @@ impl<T> [T] {
/// assert!(match r { Ok(1..=4) => true, _ => false, });
/// ```
///
+ /// If you want to find that whole *range* of matching items, rather than
+ /// an arbitrary matching one, that can be done using [`partition_point`]:
+ /// ```
+ /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+ ///
+ /// let low = s.partition_point(|x| x < &1);
+ /// assert_eq!(low, 1);
+ /// let high = s.partition_point(|x| x <= &1);
+ /// assert_eq!(high, 5);
+ /// let r = s.binary_search(&1);
+ /// assert!((low..high).contains(&r.unwrap()));
+ ///
+ /// assert!(s[..low].iter().all(|&x| x < 1));
+ /// assert!(s[low..high].iter().all(|&x| x == 1));
+ /// assert!(s[high..].iter().all(|&x| x > 1));
+ ///
+ /// // For something not found, the "range" of equal items is empty
+ /// assert_eq!(s.partition_point(|x| x < &11), 9);
+ /// assert_eq!(s.partition_point(|x| x <= &11), 9);
+ /// assert_eq!(s.binary_search(&11), Err(9));
+ /// ```
+ ///
/// If you want to insert an item to a sorted vector, while maintaining
/// sort order, consider using [`partition_point`]:
///
@@ -2409,15 +2453,20 @@ impl<T> [T] {
where
F: FnMut(&'a T) -> Ordering,
{
+ // INVARIANTS:
+ // - 0 <= left <= left + size = right <= self.len()
+ // - f returns Less for everything in self[..left]
+ // - f returns Greater for everything in self[right..]
let mut size = self.len();
let mut left = 0;
let mut right = size;
while left < right {
let mid = left + size / 2;
- // SAFETY: the call is made safe by the following invariants:
- // - `mid >= 0`
- // - `mid < size`: `mid` is limited by `[left; right)` bound.
+ // SAFETY: the while condition means `size` is strictly positive, so
+ // `size/2 < size`. Thus `left + size/2 < left + size`, which
+ // coupled with the `left + size <= self.len()` invariant means
+ // we have `left + size/2 < self.len()`, and this is in-bounds.
let cmp = f(unsafe { self.get_unchecked(mid) });
// The reason why we use if/else control flow rather than match
@@ -2435,6 +2484,10 @@ impl<T> [T] {
size = right - left;
}
+
+ // SAFETY: directly true from the overall invariant.
+ // Note that this is `<=`, unlike the assume in the `Ok` path.
+ unsafe { crate::intrinsics::assume(left <= self.len()) };
Err(left)
}
@@ -2525,7 +2578,7 @@ impl<T> [T] {
where
T: Ord,
{
- sort::quicksort(self, |a, b| a.lt(b));
+ sort::quicksort(self, T::lt);
}
/// Sorts the slice with a comparator function, but might not preserve the order of equal
@@ -2628,9 +2681,10 @@ impl<T> [T] {
/// less than or equal to any value at a position `j > index`. Additionally, this reordering is
/// unstable (i.e. any number of equal elements may end up at position `index`), in-place
/// (i.e. does not allocate), and *O*(*n*) worst-case. This function is also/ known as "kth
- /// element" in other libraries. It returns a triplet of the following values: all elements less
- /// than the one at the given index, the value at the given index, and all elements greater than
- /// the one at the given index.
+ /// element" in other libraries. It returns a triplet of the following from the reordered slice:
+ /// the subslice prior to `index`, the element at `index`, and the subslice after `index`;
+ /// accordingly, the values in those two subslices will respectively all be less-than-or-equal-to
+ /// and greater-than-or-equal-to the value of the element at `index`.
///
/// # Current implementation
///
@@ -2664,8 +2718,7 @@ impl<T> [T] {
where
T: Ord,
{
- let mut f = |a: &T, b: &T| a.lt(b);
- sort::partition_at_index(self, index, &mut f)
+ sort::partition_at_index(self, index, T::lt)
}
/// Reorder the slice with a comparator function such that the element at `index` is at its
@@ -2675,10 +2728,11 @@ impl<T> [T] {
/// less than or equal to any value at a position `j > index` using the comparator function.
/// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
/// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
- /// is also known as "kth element" in other libraries. It returns a triplet of the following
- /// values: all elements less than the one at the given index, the value at the given index,
- /// and all elements greater than the one at the given index, using the provided comparator
- /// function.
+ /// is also known as "kth element" in other libraries. It returns a triplet of the following from
+ /// the slice reordered according to the provided comparator function: the subslice prior to
+ /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in
+ /// those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to
+ /// the value of the element at `index`.
///
/// # Current implementation
///
@@ -2716,8 +2770,7 @@ impl<T> [T] {
where
F: FnMut(&T, &T) -> Ordering,
{
- let mut f = |a: &T, b: &T| compare(a, b) == Less;
- sort::partition_at_index(self, index, &mut f)
+ sort::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less)
}
/// Reorder the slice with a key extraction function such that the element at `index` is at its
@@ -2727,10 +2780,11 @@ impl<T> [T] {
/// less than or equal to any value at a position `j > index` using the key extraction function.
/// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
/// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
- /// is also known as "kth element" in other libraries. It returns a triplet of the following
- /// values: all elements less than the one at the given index, the value at the given index, and
- /// all elements greater than the one at the given index, using the provided key extraction
- /// function.
+ /// is also known as "kth element" in other libraries. It returns a triplet of the following from
+ /// the slice reordered according to the provided key extraction function: the subslice prior to
+ /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in
+ /// those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to
+ /// the value of the element at `index`.
///
/// # Current implementation
///
@@ -2769,8 +2823,7 @@ impl<T> [T] {
F: FnMut(&T) -> K,
K: Ord,
{
- let mut g = |a: &T, b: &T| f(a).lt(&f(b));
- sort::partition_at_index(self, index, &mut g)
+ sort::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b)))
}
/// Moves all consecutive repeated elements to the end of the slice according to the
@@ -2921,7 +2974,7 @@ impl<T> [T] {
let prev_ptr_write = ptr.add(next_write - 1);
if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) {
if next_read != next_write {
- let ptr_write = prev_ptr_write.offset(1);
+ let ptr_write = prev_ptr_write.add(1);
mem::swap(&mut *ptr_read, &mut *ptr_write);
}
next_write += 1;
@@ -3444,7 +3497,7 @@ impl<T> [T] {
#[must_use]
pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T]) {
// Note that most of this function will be constant-evaluated,
- if mem::size_of::<U>() == 0 || mem::size_of::<T>() == 0 {
+ if U::IS_ZST || T::IS_ZST {
// handle ZSTs specially, which is – don't handle them at all.
return (self, &[], &[]);
}
@@ -3505,7 +3558,7 @@ impl<T> [T] {
#[must_use]
pub unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) {
// Note that most of this function will be constant-evaluated,
- if mem::size_of::<U>() == 0 || mem::size_of::<T>() == 0 {
+ if U::IS_ZST || T::IS_ZST {
// handle ZSTs specially, which is – don't handle them at all.
return (self, &mut [], &mut []);
}
@@ -3518,7 +3571,7 @@ impl<T> [T] {
// alignment targeted for U.
// `crate::ptr::align_offset` is called with a correctly aligned and
// valid pointer `ptr` (it comes from a reference to `self`) and with
- // a size that is a power of two (since it comes from the alignement for U),
+ // a size that is a power of two (since it comes from the alignment for U),
// satisfying its safety constraints.
let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::<U>()) };
if offset > self.len() {
@@ -3761,6 +3814,16 @@ impl<T> [T] {
/// assert!(v[i..].iter().all(|&x| !(x < 5)));
/// ```
///
+ /// If all elements of the slice match the predicate, including if the slice
+ /// is empty, then the length of the slice will be returned:
+ ///
+ /// ```
+ /// let a = [2, 4, 8];
+ /// assert_eq!(a.partition_point(|x| x < &100), a.len());
+ /// let a: [i32; 0] = [];
+ /// assert_eq!(a.partition_point(|x| x < &100), 0);
+ /// ```
+ ///
/// If you want to insert an item to a sorted vector, while maintaining
/// sort order:
///
@@ -4051,7 +4114,7 @@ impl<T, const N: usize> [[T; N]] {
/// ```
#[unstable(feature = "slice_flatten", issue = "95629")]
pub fn flatten(&self) -> &[T] {
- let len = if crate::mem::size_of::<T>() == 0 {
+ let len = if T::IS_ZST {
self.len().checked_mul(N).expect("slice len overflow")
} else {
// SAFETY: `self.len() * N` cannot overflow because `self` is
@@ -4089,7 +4152,7 @@ impl<T, const N: usize> [[T; N]] {
/// ```
#[unstable(feature = "slice_flatten", issue = "95629")]
pub fn flatten_mut(&mut self) -> &mut [T] {
- let len = if crate::mem::size_of::<T>() == 0 {
+ let len = if T::IS_ZST {
self.len().checked_mul(N).expect("slice len overflow")
} else {
// SAFETY: `self.len() * N` cannot overflow because `self` is
@@ -4101,7 +4164,6 @@ impl<T, const N: usize> [[T; N]] {
}
}
-#[cfg(not(bootstrap))]
#[cfg(not(test))]
impl [f32] {
/// Sorts the slice of floats.
@@ -4131,7 +4193,6 @@ impl [f32] {
}
}
-#[cfg(not(bootstrap))]
#[cfg(not(test))]
impl [f64] {
/// Sorts the slice of floats.
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index 107e71ab6..052fd34d0 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -1,7 +1,9 @@
//! Free functions to create `&[T]` and `&mut [T]`.
use crate::array;
-use crate::intrinsics::{assert_unsafe_precondition, is_aligned_and_not_null};
+use crate::intrinsics::{
+ assert_unsafe_precondition, is_aligned_and_not_null, is_valid_allocation_size,
+};
use crate::ops::Range;
use crate::ptr;
@@ -91,8 +93,9 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
// SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
unsafe {
assert_unsafe_precondition!(
- is_aligned_and_not_null(data)
- && crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize
+ "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
+ [T](data: *const T, len: usize) => is_aligned_and_not_null(data)
+ && is_valid_allocation_size::<T>(len)
);
&*ptr::slice_from_raw_parts(data, len)
}
@@ -135,8 +138,9 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
unsafe {
assert_unsafe_precondition!(
- is_aligned_and_not_null(data)
- && crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize
+ "slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
+ [T](data: *mut T, len: usize) => is_aligned_and_not_null(data)
+ && is_valid_allocation_size::<T>(len)
);
&mut *ptr::slice_from_raw_parts_mut(data, len)
}
@@ -188,6 +192,10 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
///
/// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements.
///
+/// # Panics
+///
+/// This function panics if `T` is a Zero-Sized Type (“ZST”).
+///
/// # Caveat
///
/// The lifetime for the returned slice is inferred from its usage. To
@@ -219,9 +227,15 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
}
-/// Performs the same functionality as [`from_ptr_range`], except that a
+/// Forms a mutable slice from a pointer range.
+///
+/// This is the same functionality as [`from_ptr_range`], except that a
/// mutable slice is returned.
///
+/// This function is useful for interacting with foreign interfaces which
+/// use two pointers to refer to a range of elements in memory, as is
+/// common in C++.
+///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
@@ -247,6 +261,18 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
///
/// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements.
///
+/// # Panics
+///
+/// This function panics if `T` is a Zero-Sized Type (“ZST”).
+///
+/// # Caveat
+///
+/// The lifetime for the returned slice is inferred from its usage. To
+/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
+/// source lifetime is safe in the context, such as by providing a helper
+/// function taking the lifetime of a host value for the slice, or by explicit
+/// annotation.
+///
/// # Examples
///
/// ```
diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs
index 4589c6c0f..fa8c238f8 100644
--- a/library/core/src/slice/rotate.rs
+++ b/library/core/src/slice/rotate.rs
@@ -1,5 +1,5 @@
use crate::cmp;
-use crate::mem::{self, MaybeUninit};
+use crate::mem::{self, MaybeUninit, SizedTypeProperties};
use crate::ptr;
/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first
@@ -63,7 +63,7 @@ use crate::ptr;
/// when `left < right` the swapping happens from the left instead.
pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
type BufType = [usize; 32];
- if mem::size_of::<T>() == 0 {
+ if T::IS_ZST {
return;
}
loop {
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 6a201834b..87f77b7f2 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -7,7 +7,7 @@
//! stable sorting implementation.
use crate::cmp;
-use crate::mem::{self, MaybeUninit};
+use crate::mem::{self, MaybeUninit, SizedTypeProperties};
use crate::ptr;
/// When dropped, copies from `src` into `dest`.
@@ -326,8 +326,8 @@ where
unsafe {
// Branchless comparison.
*end_l = i as u8;
- end_l = end_l.offset(!is_less(&*elem, pivot) as isize);
- elem = elem.offset(1);
+ end_l = end_l.add(!is_less(&*elem, pivot) as usize);
+ elem = elem.add(1);
}
}
}
@@ -352,9 +352,9 @@ where
// Plus, `block_r` was asserted to be less than `BLOCK` and `elem` will therefore at most be pointing to the beginning of the slice.
unsafe {
// Branchless comparison.
- elem = elem.offset(-1);
+ elem = elem.sub(1);
*end_r = i as u8;
- end_r = end_r.offset(is_less(&*elem, pivot) as isize);
+ end_r = end_r.add(is_less(&*elem, pivot) as usize);
}
}
}
@@ -365,12 +365,12 @@ where
if count > 0 {
macro_rules! left {
() => {
- l.offset(*start_l as isize)
+ l.add(usize::from(*start_l))
};
}
macro_rules! right {
() => {
- r.offset(-(*start_r as isize) - 1)
+ r.sub(usize::from(*start_r) + 1)
};
}
@@ -398,16 +398,16 @@ where
ptr::copy_nonoverlapping(right!(), left!(), 1);
for _ in 1..count {
- start_l = start_l.offset(1);
+ start_l = start_l.add(1);
ptr::copy_nonoverlapping(left!(), right!(), 1);
- start_r = start_r.offset(1);
+ start_r = start_r.add(1);
ptr::copy_nonoverlapping(right!(), left!(), 1);
}
ptr::copy_nonoverlapping(&tmp, right!(), 1);
mem::forget(tmp);
- start_l = start_l.offset(1);
- start_r = start_r.offset(1);
+ start_l = start_l.add(1);
+ start_r = start_r.add(1);
}
}
@@ -420,7 +420,7 @@ where
// safe. Otherwise, the debug assertions in the `is_done` case guarantee that
// `width(l, r) == block_l + block_r`, namely, that the block sizes have been adjusted to account
// for the smaller number of remaining elements.
- l = unsafe { l.offset(block_l as isize) };
+ l = unsafe { l.add(block_l) };
}
if start_r == end_r {
@@ -428,7 +428,7 @@ where
// SAFETY: Same argument as [block-width-guarantee]. Either this is a full block `2*BLOCK`-wide,
// or `block_r` has been adjusted for the last handful of elements.
- r = unsafe { r.offset(-(block_r as isize)) };
+ r = unsafe { r.sub(block_r) };
}
if is_done {
@@ -457,9 +457,9 @@ where
// - `offsets_l` contains valid offsets into `v` collected during the partitioning of
// the last block, so the `l.offset` calls are valid.
unsafe {
- end_l = end_l.offset(-1);
- ptr::swap(l.offset(*end_l as isize), r.offset(-1));
- r = r.offset(-1);
+ end_l = end_l.sub(1);
+ ptr::swap(l.add(usize::from(*end_l)), r.sub(1));
+ r = r.sub(1);
}
}
width(v.as_mut_ptr(), r)
@@ -470,9 +470,9 @@ where
while start_r < end_r {
// SAFETY: See the reasoning in [remaining-elements-safety].
unsafe {
- end_r = end_r.offset(-1);
- ptr::swap(l, r.offset(-(*end_r as isize) - 1));
- l = l.offset(1);
+ end_r = end_r.sub(1);
+ ptr::swap(l, r.sub(usize::from(*end_r) + 1));
+ l = l.add(1);
}
}
width(v.as_mut_ptr(), l)
@@ -813,7 +813,7 @@ where
F: FnMut(&T, &T) -> bool,
{
// Sorting has no meaningful behavior on zero-sized types.
- if mem::size_of::<T>() == 0 {
+ if T::IS_ZST {
return;
}
@@ -898,7 +898,7 @@ where
panic!("partition_at_index index {} greater than length of slice {}", index, v.len());
}
- if mem::size_of::<T>() == 0 {
+ if T::IS_ZST {
// Sorting has no meaningful behavior on zero-sized types. Do nothing.
} else if index == v.len() - 1 {
// Find max element and place it in the last position of the array. We're free to use
diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs
index 4e569fcc8..a11b5add4 100644
--- a/library/core/src/str/error.rs
+++ b/library/core/src/str/error.rs
@@ -1,5 +1,6 @@
//! Defines utf8 error type.
+use crate::error::Error;
use crate::fmt;
/// Errors which can occur when attempting to interpret a sequence of [`u8`]
@@ -122,6 +123,14 @@ impl fmt::Display for Utf8Error {
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for Utf8Error {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "invalid utf-8: corrupt contents"
+ }
+}
+
/// An error returned when parsing a `bool` using [`from_str`] fails
///
/// [`from_str`]: super::FromStr::from_str
@@ -136,3 +145,11 @@ impl fmt::Display for ParseBoolError {
"provided string was not `true` or `false`".fmt(f)
}
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for ParseBoolError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "failed to parse bool"
+ }
+}
diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs
index 6ec1c9390..59f873d12 100644
--- a/library/core/src/str/lossy.rs
+++ b/library/core/src/str/lossy.rs
@@ -1,51 +1,170 @@
-use crate::char;
-use crate::fmt::{self, Write};
-use crate::mem;
+use crate::fmt;
+use crate::fmt::Formatter;
+use crate::fmt::Write;
+use crate::iter::FusedIterator;
use super::from_utf8_unchecked;
use super::validations::utf8_char_width;
-/// Lossy UTF-8 string.
-#[unstable(feature = "str_internals", issue = "none")]
-pub struct Utf8Lossy {
- bytes: [u8],
+/// An item returned by the [`Utf8Chunks`] iterator.
+///
+/// A `Utf8Chunk` stores a sequence of [`u8`] up to the first broken character
+/// when decoding a UTF-8 string.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(utf8_chunks)]
+///
+/// use std::str::Utf8Chunks;
+///
+/// // An invalid UTF-8 string
+/// let bytes = b"foo\xF1\x80bar";
+///
+/// // Decode the first `Utf8Chunk`
+/// let chunk = Utf8Chunks::new(bytes).next().unwrap();
+///
+/// // The first three characters are valid UTF-8
+/// assert_eq!("foo", chunk.valid());
+///
+/// // The fourth character is broken
+/// assert_eq!(b"\xF1\x80", chunk.invalid());
+/// ```
+#[unstable(feature = "utf8_chunks", issue = "99543")]
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct Utf8Chunk<'a> {
+ valid: &'a str,
+ invalid: &'a [u8],
}
-impl Utf8Lossy {
+impl<'a> Utf8Chunk<'a> {
+ /// Returns the next validated UTF-8 substring.
+ ///
+ /// This substring can be empty at the start of the string or between
+ /// broken UTF-8 characters.
#[must_use]
- pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy {
- // SAFETY: Both use the same memory layout, and UTF-8 correctness isn't required.
- unsafe { mem::transmute(bytes) }
+ #[unstable(feature = "utf8_chunks", issue = "99543")]
+ pub fn valid(&self) -> &'a str {
+ self.valid
}
- pub fn chunks(&self) -> Utf8LossyChunksIter<'_> {
- Utf8LossyChunksIter { source: &self.bytes }
+ /// Returns the invalid sequence that caused a failure.
+ ///
+ /// The returned slice will have a maximum length of 3 and starts after the
+ /// substring given by [`valid`]. Decoding will resume after this sequence.
+ ///
+ /// If empty, this is the last chunk in the string. If non-empty, an
+ /// unexpected byte was encountered or the end of the input was reached
+ /// unexpectedly.
+ ///
+ /// Lossy decoding would replace this sequence with [`U+FFFD REPLACEMENT
+ /// CHARACTER`].
+ ///
+ /// [`valid`]: Self::valid
+ /// [`U+FFFD REPLACEMENT CHARACTER`]: crate::char::REPLACEMENT_CHARACTER
+ #[must_use]
+ #[unstable(feature = "utf8_chunks", issue = "99543")]
+ pub fn invalid(&self) -> &'a [u8] {
+ self.invalid
}
}
-/// Iterator over lossy UTF-8 string
-#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[must_use]
+#[unstable(feature = "str_internals", issue = "none")]
+pub struct Debug<'a>(&'a [u8]);
+
#[unstable(feature = "str_internals", issue = "none")]
-#[allow(missing_debug_implementations)]
-pub struct Utf8LossyChunksIter<'a> {
+impl fmt::Debug for Debug<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.write_char('"')?;
+
+ for chunk in Utf8Chunks::new(self.0) {
+ // Valid part.
+ // Here we partially parse UTF-8 again which is suboptimal.
+ {
+ let valid = chunk.valid();
+ let mut from = 0;
+ for (i, c) in valid.char_indices() {
+ let esc = c.escape_debug();
+ // If char needs escaping, flush backlog so far and write, else skip
+ if esc.len() != 1 {
+ f.write_str(&valid[from..i])?;
+ for c in esc {
+ f.write_char(c)?;
+ }
+ from = i + c.len_utf8();
+ }
+ }
+ f.write_str(&valid[from..])?;
+ }
+
+ // Broken parts of string as hex escape.
+ for &b in chunk.invalid() {
+ write!(f, "\\x{:02X}", b)?;
+ }
+ }
+
+ f.write_char('"')
+ }
+}
+
+/// An iterator used to decode a slice of mostly UTF-8 bytes to string slices
+/// ([`&str`]) and byte slices ([`&[u8]`][byteslice]).
+///
+/// If you want a simple conversion from UTF-8 byte slices to string slices,
+/// [`from_utf8`] is easier to use.
+///
+/// [byteslice]: slice
+/// [`from_utf8`]: super::from_utf8
+///
+/// # Examples
+///
+/// This can be used to create functionality similar to
+/// [`String::from_utf8_lossy`] without allocating heap memory:
+///
+/// ```
+/// #![feature(utf8_chunks)]
+///
+/// use std::str::Utf8Chunks;
+///
+/// fn from_utf8_lossy<F>(input: &[u8], mut push: F) where F: FnMut(&str) {
+/// for chunk in Utf8Chunks::new(input) {
+/// push(chunk.valid());
+///
+/// if !chunk.invalid().is_empty() {
+/// push("\u{FFFD}");
+/// }
+/// }
+/// }
+/// ```
+///
+/// [`String::from_utf8_lossy`]: ../../std/string/struct.String.html#method.from_utf8_lossy
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "utf8_chunks", issue = "99543")]
+#[derive(Clone)]
+pub struct Utf8Chunks<'a> {
source: &'a [u8],
}
-#[unstable(feature = "str_internals", issue = "none")]
-#[derive(PartialEq, Eq, Debug)]
-pub struct Utf8LossyChunk<'a> {
- /// Sequence of valid chars.
- /// Can be empty between broken UTF-8 chars.
- pub valid: &'a str,
- /// Single broken char, empty if none.
- /// Empty iff iterator item is last.
- pub broken: &'a [u8],
+impl<'a> Utf8Chunks<'a> {
+ /// Creates a new iterator to decode the bytes.
+ #[unstable(feature = "utf8_chunks", issue = "99543")]
+ pub fn new(bytes: &'a [u8]) -> Self {
+ Self { source: bytes }
+ }
+
+ #[doc(hidden)]
+ #[unstable(feature = "str_internals", issue = "none")]
+ pub fn debug(&self) -> Debug<'_> {
+ Debug(self.source)
+ }
}
-impl<'a> Iterator for Utf8LossyChunksIter<'a> {
- type Item = Utf8LossyChunk<'a>;
+#[unstable(feature = "utf8_chunks", issue = "99543")]
+impl<'a> Iterator for Utf8Chunks<'a> {
+ type Item = Utf8Chunk<'a>;
- fn next(&mut self) -> Option<Utf8LossyChunk<'a>> {
+ fn next(&mut self) -> Option<Utf8Chunk<'a>> {
if self.source.is_empty() {
return None;
}
@@ -130,71 +249,22 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> {
// SAFETY: `valid_up_to <= i` because it is only ever assigned via
// `valid_up_to = i` and `i` only increases.
- let (valid, broken) = unsafe { inspected.split_at_unchecked(valid_up_to) };
+ let (valid, invalid) = unsafe { inspected.split_at_unchecked(valid_up_to) };
- Some(Utf8LossyChunk {
+ Some(Utf8Chunk {
// SAFETY: All bytes up to `valid_up_to` are valid UTF-8.
valid: unsafe { from_utf8_unchecked(valid) },
- broken,
+ invalid,
})
}
}
-impl fmt::Display for Utf8Lossy {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // If we're the empty string then our iterator won't actually yield
- // anything, so perform the formatting manually
- if self.bytes.is_empty() {
- return "".fmt(f);
- }
-
- for Utf8LossyChunk { valid, broken } in self.chunks() {
- // If we successfully decoded the whole chunk as a valid string then
- // we can return a direct formatting of the string which will also
- // respect various formatting flags if possible.
- if valid.len() == self.bytes.len() {
- assert!(broken.is_empty());
- return valid.fmt(f);
- }
-
- f.write_str(valid)?;
- if !broken.is_empty() {
- f.write_char(char::REPLACEMENT_CHARACTER)?;
- }
- }
- Ok(())
- }
-}
-
-impl fmt::Debug for Utf8Lossy {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_char('"')?;
+#[unstable(feature = "utf8_chunks", issue = "99543")]
+impl FusedIterator for Utf8Chunks<'_> {}
- for Utf8LossyChunk { valid, broken } in self.chunks() {
- // Valid part.
- // Here we partially parse UTF-8 again which is suboptimal.
- {
- let mut from = 0;
- for (i, c) in valid.char_indices() {
- let esc = c.escape_debug();
- // If char needs escaping, flush backlog so far and write, else skip
- if esc.len() != 1 {
- f.write_str(&valid[from..i])?;
- for c in esc {
- f.write_char(c)?;
- }
- from = i + c.len_utf8();
- }
- }
- f.write_str(&valid[from..])?;
- }
-
- // Broken parts of string as hex escape.
- for &b in broken {
- write!(f, "\\x{:02x}", b)?;
- }
- }
-
- f.write_char('"')
+#[unstable(feature = "utf8_chunks", issue = "99543")]
+impl fmt::Debug for Utf8Chunks<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Utf8Chunks").field("source", &self.debug()).finish()
}
}
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index c4f2e283e..fbc0fc397 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -22,9 +22,9 @@ use crate::slice::{self, SliceIndex};
pub mod pattern;
-#[unstable(feature = "str_internals", issue = "none")]
-#[allow(missing_docs)]
-pub mod lossy;
+mod lossy;
+#[unstable(feature = "utf8_chunks", issue = "99543")]
+pub use lossy::{Utf8Chunk, Utf8Chunks};
#[stable(feature = "rust1", since = "1.0.0")]
pub use converts::{from_utf8, from_utf8_unchecked};
@@ -91,10 +91,12 @@ const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
}
}
+#[track_caller]
const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! {
panic!("failed to slice string");
}
+#[track_caller]
fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! {
const MAX_DISPLAY_LENGTH: usize = 256;
let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH);
@@ -2353,7 +2355,7 @@ impl str {
#[inline]
pub fn is_ascii(&self) -> bool {
// We can treat each byte as character here: all multibyte characters
- // start with a byte that is not in the ascii range, so we will stop
+ // start with a byte that is not in the ASCII range, so we will stop
// there already.
self.as_bytes().is_ascii()
}
@@ -2638,3 +2640,6 @@ impl_fn_for_zst! {
unsafe { from_utf8_unchecked(bytes) }
};
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl !crate::error::Error for &str {}
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index 031fb8e8b..ec2cb429e 100644
--- a/library/core/src/str/pattern.rs
+++ b/library/core/src/str/pattern.rs
@@ -267,7 +267,7 @@ pub unsafe trait Searcher<'a> {
/// The index ranges returned by this trait are not required
/// to exactly match those of the forward search in reverse.
///
-/// For the reason why this trait is marked unsafe, see them
+/// For the reason why this trait is marked unsafe, see the
/// parent trait [`Searcher`].
pub unsafe trait ReverseSearcher<'a>: Searcher<'a> {
/// Performs the next search step starting from the back.
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index e9649fc91..d3ed811b1 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -507,7 +507,6 @@ unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
///
/// ```
/// use std::str::FromStr;
-/// use std::num::ParseIntError;
///
/// #[derive(Debug, PartialEq)]
/// struct Point {
@@ -515,18 +514,21 @@ unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
/// y: i32
/// }
///
+/// #[derive(Debug, PartialEq, Eq)]
+/// struct ParsePointError;
+///
/// impl FromStr for Point {
-/// type Err = ParseIntError;
+/// type Err = ParsePointError;
///
/// fn from_str(s: &str) -> Result<Self, Self::Err> {
/// let (x, y) = s
/// .strip_prefix('(')
/// .and_then(|s| s.strip_suffix(')'))
/// .and_then(|s| s.split_once(','))
-/// .unwrap();
+/// .ok_or(ParsePointError)?;
///
-/// let x_fromstr = x.parse::<i32>()?;
-/// let y_fromstr = y.parse::<i32>()?;
+/// let x_fromstr = x.parse::<i32>().map_err(|_| ParsePointError)?;
+/// let y_fromstr = y.parse::<i32>().map_err(|_| ParsePointError)?;
///
/// Ok(Point { x: x_fromstr, y: y_fromstr })
/// }
@@ -538,6 +540,8 @@ unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
/// // Implicit calls, through parse
/// assert_eq!("(1,2)".parse(), expected);
/// assert_eq!("(1,2)".parse::<Point>(), expected);
+/// // Invalid input string
+/// assert!(Point::from_str("(1 2)").is_err());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait FromStr: Sized {
@@ -573,8 +577,8 @@ impl FromStr for bool {
/// Parse a `bool` from a string.
///
- /// Yields a `Result<bool, ParseBoolError>`, because `s` may or may not
- /// actually be parseable.
+ /// The only accepted values are `"true"` and `"false"`. Any other input
+ /// will return an error.
///
/// # Examples
///
diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs
index 04bc66523..2acef432f 100644
--- a/library/core/src/str/validations.rs
+++ b/library/core/src/str/validations.rs
@@ -216,12 +216,12 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
// SAFETY: since `align - index` and `ascii_block_size` are
// multiples of `usize_bytes`, `block = ptr.add(index)` is
// always aligned with a `usize` so it's safe to dereference
- // both `block` and `block.offset(1)`.
+ // both `block` and `block.add(1)`.
unsafe {
let block = ptr.add(index) as *const usize;
// break if there is a nonascii byte
let zu = contains_nonascii(*block);
- let zv = contains_nonascii(*block.offset(1));
+ let zv = contains_nonascii(*block.add(1));
if zu || zv {
break;
}
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 5e2e0c4d8..edc68d6fa 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -294,7 +294,7 @@ impl AtomicBool {
/// ```
/// use std::sync::atomic::AtomicBool;
///
- /// let atomic_true = AtomicBool::new(true);
+ /// let atomic_true = AtomicBool::new(true);
/// let atomic_false = AtomicBool::new(false);
/// ```
#[inline]
@@ -955,6 +955,14 @@ impl AtomicBool {
/// **Note:** This method is only available on platforms that support atomic
/// operations on `u8`.
///
+ /// # Considerations
+ ///
+ /// This method is not magic; it is not provided by the hardware.
+ /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
+ /// In particular, this method will not circumvent the [ABA Problem].
+ ///
+ /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+ ///
/// # Examples
///
/// ```rust
@@ -1171,7 +1179,7 @@ impl<T> AtomicPtr<T> {
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
/// let ptr = &mut 5;
- /// let some_ptr = AtomicPtr::new(ptr);
+ /// let some_ptr = AtomicPtr::new(ptr);
///
/// let value = some_ptr.load(Ordering::Relaxed);
/// ```
@@ -1198,7 +1206,7 @@ impl<T> AtomicPtr<T> {
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
/// let ptr = &mut 5;
- /// let some_ptr = AtomicPtr::new(ptr);
+ /// let some_ptr = AtomicPtr::new(ptr);
///
/// let other_ptr = &mut 10;
///
@@ -1230,7 +1238,7 @@ impl<T> AtomicPtr<T> {
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
/// let ptr = &mut 5;
- /// let some_ptr = AtomicPtr::new(ptr);
+ /// let some_ptr = AtomicPtr::new(ptr);
///
/// let other_ptr = &mut 10;
///
@@ -1282,9 +1290,9 @@ impl<T> AtomicPtr<T> {
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
/// let ptr = &mut 5;
- /// let some_ptr = AtomicPtr::new(ptr);
+ /// let some_ptr = AtomicPtr::new(ptr);
///
- /// let other_ptr = &mut 10;
+ /// let other_ptr = &mut 10;
///
/// let value = some_ptr.compare_and_swap(ptr, other_ptr, Ordering::Relaxed);
/// ```
@@ -1325,9 +1333,9 @@ impl<T> AtomicPtr<T> {
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
/// let ptr = &mut 5;
- /// let some_ptr = AtomicPtr::new(ptr);
+ /// let some_ptr = AtomicPtr::new(ptr);
///
- /// let other_ptr = &mut 10;
+ /// let other_ptr = &mut 10;
///
/// let value = some_ptr.compare_exchange(ptr, other_ptr,
/// Ordering::SeqCst, Ordering::Relaxed);
@@ -1422,6 +1430,14 @@ impl<T> AtomicPtr<T> {
/// **Note:** This method is only available on platforms that support atomic
/// operations on pointers.
///
+ /// # Considerations
+ ///
+ /// This method is not magic; it is not provided by the hardware.
+ /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
+ /// In particular, this method will not circumvent the [ABA Problem].
+ ///
+ /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+ ///
/// # Examples
///
/// ```rust
@@ -1554,8 +1570,8 @@ impl<T> AtomicPtr<T> {
/// Offsets the pointer's address by adding `val` *bytes*, returning the
/// previous pointer.
///
- /// This is equivalent to using [`wrapping_add`] and [`cast`] to atomically
- /// perform `ptr = ptr.cast::<u8>().wrapping_add(val).cast::<T>()`.
+ /// This is equivalent to using [`wrapping_byte_add`] to atomically
+ /// perform `ptr = ptr.wrapping_byte_add(val)`.
///
/// `fetch_byte_add` takes an [`Ordering`] argument which describes the
/// memory ordering of this operation. All ordering modes are possible. Note
@@ -1565,8 +1581,7 @@ impl<T> AtomicPtr<T> {
/// **Note**: This method is only available on platforms that support atomic
/// operations on [`AtomicPtr`].
///
- /// [`wrapping_add`]: pointer::wrapping_add
- /// [`cast`]: pointer::cast
+ /// [`wrapping_byte_add`]: pointer::wrapping_byte_add
///
/// # Examples
///
@@ -1584,23 +1599,15 @@ impl<T> AtomicPtr<T> {
#[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T {
- #[cfg(not(bootstrap))]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast()
- }
- #[cfg(bootstrap)]
// SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_add(self.p.get().cast::<usize>(), val, order) as *mut T
- }
+ unsafe { atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast() }
}
/// Offsets the pointer's address by subtracting `val` *bytes*, returning the
/// previous pointer.
///
- /// This is equivalent to using [`wrapping_sub`] and [`cast`] to atomically
- /// perform `ptr = ptr.cast::<u8>().wrapping_sub(val).cast::<T>()`.
+ /// This is equivalent to using [`wrapping_byte_sub`] to atomically
+ /// perform `ptr = ptr.wrapping_byte_sub(val)`.
///
/// `fetch_byte_sub` takes an [`Ordering`] argument which describes the
/// memory ordering of this operation. All ordering modes are possible. Note
@@ -1610,8 +1617,7 @@ impl<T> AtomicPtr<T> {
/// **Note**: This method is only available on platforms that support atomic
/// operations on [`AtomicPtr`].
///
- /// [`wrapping_sub`]: pointer::wrapping_sub
- /// [`cast`]: pointer::cast
+ /// [`wrapping_byte_sub`]: pointer::wrapping_byte_sub
///
/// # Examples
///
@@ -1628,24 +1634,16 @@ impl<T> AtomicPtr<T> {
#[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T {
- #[cfg(not(bootstrap))]
// SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_sub(self.p.get(), core::ptr::invalid_mut(val), order).cast()
- }
- #[cfg(bootstrap)]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_sub(self.p.get().cast::<usize>(), val, order) as *mut T
- }
+ unsafe { atomic_sub(self.p.get(), core::ptr::invalid_mut(val), order).cast() }
}
/// Performs a bitwise "or" operation on the address of the current pointer,
/// and the argument `val`, and stores a pointer with provenance of the
/// current pointer and the resulting address.
///
- /// This is equivalent equivalent to using [`map_addr`] to atomically
- /// perform `ptr = ptr.map_addr(|a| a | val)`. This can be used in tagged
+ /// This is equivalent to using [`map_addr`] to atomically perform
+ /// `ptr = ptr.map_addr(|a| a | val)`. This can be used in tagged
/// pointer schemes to atomically set tag bits.
///
/// **Caveat**: This operation returns the previous value. To compute the
@@ -1687,24 +1685,16 @@ impl<T> AtomicPtr<T> {
#[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T {
- #[cfg(not(bootstrap))]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_or(self.p.get(), core::ptr::invalid_mut(val), order).cast()
- }
- #[cfg(bootstrap)]
// SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_or(self.p.get().cast::<usize>(), val, order) as *mut T
- }
+ unsafe { atomic_or(self.p.get(), core::ptr::invalid_mut(val), order).cast() }
}
/// Performs a bitwise "and" operation on the address of the current
/// pointer, and the argument `val`, and stores a pointer with provenance of
/// the current pointer and the resulting address.
///
- /// This is equivalent equivalent to using [`map_addr`] to atomically
- /// perform `ptr = ptr.map_addr(|a| a & val)`. This can be used in tagged
+ /// This is equivalent to using [`map_addr`] to atomically perform
+ /// `ptr = ptr.map_addr(|a| a & val)`. This can be used in tagged
/// pointer schemes to atomically unset tag bits.
///
/// **Caveat**: This operation returns the previous value. To compute the
@@ -1745,24 +1735,16 @@ impl<T> AtomicPtr<T> {
#[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T {
- #[cfg(not(bootstrap))]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_and(self.p.get(), core::ptr::invalid_mut(val), order).cast()
- }
- #[cfg(bootstrap)]
// SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_and(self.p.get().cast::<usize>(), val, order) as *mut T
- }
+ unsafe { atomic_and(self.p.get(), core::ptr::invalid_mut(val), order).cast() }
}
/// Performs a bitwise "xor" operation on the address of the current
/// pointer, and the argument `val`, and stores a pointer with provenance of
/// the current pointer and the resulting address.
///
- /// This is equivalent equivalent to using [`map_addr`] to atomically
- /// perform `ptr = ptr.map_addr(|a| a ^ val)`. This can be used in tagged
+ /// This is equivalent to using [`map_addr`] to atomically perform
+ /// `ptr = ptr.map_addr(|a| a ^ val)`. This can be used in tagged
/// pointer schemes to atomically toggle tag bits.
///
/// **Caveat**: This operation returns the previous value. To compute the
@@ -1801,16 +1783,8 @@ impl<T> AtomicPtr<T> {
#[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
- #[cfg(not(bootstrap))]
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast()
- }
- #[cfg(bootstrap)]
// SAFETY: data races are prevented by atomic intrinsics.
- unsafe {
- atomic_xor(self.p.get().cast::<usize>(), val, order) as *mut T
- }
+ unsafe { atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() }
}
}
@@ -2552,6 +2526,16 @@ macro_rules! atomic_int {
/// **Note**: This method is only available on platforms that support atomic operations on
#[doc = concat!("[`", $s_int_type, "`].")]
///
+ /// # Considerations
+ ///
+ /// This method is not magic; it is not provided by the hardware.
+ /// It is implemented in terms of
+ #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
+ /// and suffers from the same drawbacks.
+ /// In particular, this method will not circumvent the [ABA Problem].
+ ///
+ /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+ ///
/// # Examples
///
/// ```rust
@@ -3073,30 +3057,22 @@ unsafe fn atomic_compare_exchange<T: Copy>(
let (val, ok) = unsafe {
match (success, failure) {
(Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed_relaxed(dst, old, new),
- #[cfg(not(bootstrap))]
(Relaxed, Acquire) => intrinsics::atomic_cxchg_relaxed_acquire(dst, old, new),
- #[cfg(not(bootstrap))]
(Relaxed, SeqCst) => intrinsics::atomic_cxchg_relaxed_seqcst(dst, old, new),
(Acquire, Relaxed) => intrinsics::atomic_cxchg_acquire_relaxed(dst, old, new),
(Acquire, Acquire) => intrinsics::atomic_cxchg_acquire_acquire(dst, old, new),
- #[cfg(not(bootstrap))]
(Acquire, SeqCst) => intrinsics::atomic_cxchg_acquire_seqcst(dst, old, new),
(Release, Relaxed) => intrinsics::atomic_cxchg_release_relaxed(dst, old, new),
- #[cfg(not(bootstrap))]
(Release, Acquire) => intrinsics::atomic_cxchg_release_acquire(dst, old, new),
- #[cfg(not(bootstrap))]
(Release, SeqCst) => intrinsics::atomic_cxchg_release_seqcst(dst, old, new),
(AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_relaxed(dst, old, new),
(AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel_acquire(dst, old, new),
- #[cfg(not(bootstrap))]
(AcqRel, SeqCst) => intrinsics::atomic_cxchg_acqrel_seqcst(dst, old, new),
(SeqCst, Relaxed) => intrinsics::atomic_cxchg_seqcst_relaxed(dst, old, new),
(SeqCst, Acquire) => intrinsics::atomic_cxchg_seqcst_acquire(dst, old, new),
(SeqCst, SeqCst) => intrinsics::atomic_cxchg_seqcst_seqcst(dst, old, new),
(_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"),
(_, Release) => panic!("there is no such thing as a release failure ordering"),
- #[cfg(bootstrap)]
- _ => panic!("a failure ordering can't be stronger than a success ordering"),
}
};
if ok { Ok(val) } else { Err(val) }
@@ -3116,30 +3092,22 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>(
let (val, ok) = unsafe {
match (success, failure) {
(Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed_relaxed(dst, old, new),
- #[cfg(not(bootstrap))]
(Relaxed, Acquire) => intrinsics::atomic_cxchgweak_relaxed_acquire(dst, old, new),
- #[cfg(not(bootstrap))]
(Relaxed, SeqCst) => intrinsics::atomic_cxchgweak_relaxed_seqcst(dst, old, new),
(Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acquire_relaxed(dst, old, new),
(Acquire, Acquire) => intrinsics::atomic_cxchgweak_acquire_acquire(dst, old, new),
- #[cfg(not(bootstrap))]
(Acquire, SeqCst) => intrinsics::atomic_cxchgweak_acquire_seqcst(dst, old, new),
(Release, Relaxed) => intrinsics::atomic_cxchgweak_release_relaxed(dst, old, new),
- #[cfg(not(bootstrap))]
(Release, Acquire) => intrinsics::atomic_cxchgweak_release_acquire(dst, old, new),
- #[cfg(not(bootstrap))]
(Release, SeqCst) => intrinsics::atomic_cxchgweak_release_seqcst(dst, old, new),
(AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_relaxed(dst, old, new),
(AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel_acquire(dst, old, new),
- #[cfg(not(bootstrap))]
(AcqRel, SeqCst) => intrinsics::atomic_cxchgweak_acqrel_seqcst(dst, old, new),
(SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_seqcst_relaxed(dst, old, new),
(SeqCst, Acquire) => intrinsics::atomic_cxchgweak_seqcst_acquire(dst, old, new),
(SeqCst, SeqCst) => intrinsics::atomic_cxchgweak_seqcst_seqcst(dst, old, new),
(_, AcqRel) => panic!("there is no such thing as an acquire-release failure ordering"),
(_, Release) => panic!("there is no such thing as a release failure ordering"),
- #[cfg(bootstrap)]
- _ => panic!("a failure ordering can't be stronger than a success ordering"),
}
};
if ok { Ok(val) } else { Err(val) }
diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs
index a7519ab5a..c65c27500 100644
--- a/library/core/src/sync/exclusive.rs
+++ b/library/core/src/sync/exclusive.rs
@@ -100,6 +100,7 @@ impl<T: Sized> Exclusive<T> {
/// Wrap a value in an `Exclusive`
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
+ #[inline]
pub const fn new(t: T) -> Self {
Self { inner: t }
}
@@ -107,6 +108,7 @@ impl<T: Sized> Exclusive<T> {
/// Unwrap the value contained in the `Exclusive`
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
+ #[inline]
pub const fn into_inner(self) -> T {
self.inner
}
@@ -116,6 +118,7 @@ impl<T: ?Sized> Exclusive<T> {
/// Get exclusive access to the underlying value.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
+ #[inline]
pub const fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
@@ -128,6 +131,7 @@ impl<T: ?Sized> Exclusive<T> {
/// produce _pinned_ access to the underlying value.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
+ #[inline]
pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
// SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned
// `Pin::map_unchecked_mut` is not const, so we do this conversion manually
@@ -139,6 +143,7 @@ impl<T: ?Sized> Exclusive<T> {
/// building an `Exclusive` with [`Exclusive::new`].
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
+ #[inline]
pub const fn from_mut(r: &'_ mut T) -> &'_ mut Exclusive<T> {
// SAFETY: repr is ≥ C, so refs have the same layout; and `Exclusive` properties are `&mut`-agnostic
unsafe { &mut *(r as *mut T as *mut Exclusive<T>) }
@@ -149,6 +154,7 @@ impl<T: ?Sized> Exclusive<T> {
/// building an `Exclusive` with [`Exclusive::new`].
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
+ #[inline]
pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> {
// SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned
// `Pin::map_unchecked_mut` is not const, so we do this conversion manually
@@ -158,6 +164,7 @@ impl<T: ?Sized> Exclusive<T> {
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T> From<T> for Exclusive<T> {
+ #[inline]
fn from(t: T) -> Self {
Self::new(t)
}
@@ -166,7 +173,7 @@ impl<T> From<T> for Exclusive<T> {
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T: Future + ?Sized> Future for Exclusive<T> {
type Output = T::Output;
-
+ #[inline]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.get_pin_mut().poll(cx)
}
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 87d4a25af..0cff972df 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -71,6 +71,12 @@ impl RawWaker {
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
+///
+/// These functions must all be thread-safe (even though [`RawWaker`] is
+/// <code>\![Send] + \![Sync]</code>)
+/// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to
+/// arbitrary threads or invoked by `&` reference. For example, this means that if the
+/// `clone` and `drop` functions manage a reference count, they must do so atomically.
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
@@ -110,6 +116,12 @@ impl RawWakerVTable {
/// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
/// `wake_by_ref`, and `drop` functions.
///
+ /// These functions must all be thread-safe (even though [`RawWaker`] is
+ /// <code>\![Send] + \![Sync]</code>)
+ /// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to
+ /// arbitrary threads or invoked by `&` reference. For example, this means that if the
+ /// `clone` and `drop` functions manage a reference count, they must do so atomically.
+ ///
/// # `clone`
///
/// This function will be called when the [`RawWaker`] gets cloned, e.g. when
@@ -157,9 +169,9 @@ impl RawWakerVTable {
}
}
-/// The `Context` of an asynchronous task.
+/// The context of an asynchronous task.
///
-/// Currently, `Context` only serves to provide access to a `&Waker`
+/// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
/// which can be used to wake the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Context<'a> {
@@ -172,19 +184,21 @@ pub struct Context<'a> {
}
impl<'a> Context<'a> {
- /// Create a new `Context` from a `&Waker`.
+ /// Create a new `Context` from a [`&Waker`](Waker).
#[stable(feature = "futures_api", since = "1.36.0")]
+ #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
#[must_use]
#[inline]
- pub fn from_waker(waker: &'a Waker) -> Self {
+ pub const fn from_waker(waker: &'a Waker) -> Self {
Context { waker, _marker: PhantomData }
}
- /// Returns a reference to the `Waker` for the current task.
+ /// Returns a reference to the [`Waker`] for the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
+ #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
#[must_use]
#[inline]
- pub fn waker(&self) -> &'a Waker {
+ pub const fn waker(&self) -> &'a Waker {
&self.waker
}
}
@@ -202,7 +216,18 @@ impl fmt::Debug for Context<'_> {
/// This handle encapsulates a [`RawWaker`] instance, which defines the
/// executor-specific wakeup behavior.
///
-/// Implements [`Clone`], [`Send`], and [`Sync`].
+/// The typical life of a `Waker` is that it is constructed by an executor, wrapped in a
+/// [`Context`], then passed to [`Future::poll()`]. Then, if the future chooses to return
+/// [`Poll::Pending`], it must also store the waker somehow and call [`Waker::wake()`] when
+/// the future should be polled again.
+///
+/// Implements [`Clone`], [`Send`], and [`Sync`]; therefore, a waker may be invoked
+/// from any thread, including ones not in any way managed by the executor. For example,
+/// this might be done to wake a future when a blocking function call completes on another
+/// thread.
+///
+/// [`Future::poll()`]: core::future::Future::poll
+/// [`Poll::Pending`]: core::task::Poll::Pending
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
@@ -219,18 +244,21 @@ unsafe impl Sync for Waker {}
impl Waker {
/// Wake up the task associated with this `Waker`.
///
- /// As long as the runtime keeps running and the task is not finished, it is
- /// guaranteed that each invocation of `wake` (or `wake_by_ref`) will be followed
- /// by at least one `poll` of the task to which this `Waker` belongs. This makes
+ /// As long as the executor keeps running and the task is not finished, it is
+ /// guaranteed that each invocation of [`wake()`](Self::wake) (or
+ /// [`wake_by_ref()`](Self::wake_by_ref)) will be followed by at least one
+ /// [`poll()`] of the task to which this `Waker` belongs. This makes
/// it possible to temporarily yield to other tasks while running potentially
/// unbounded processing loops.
///
/// Note that the above implies that multiple wake-ups may be coalesced into a
- /// single `poll` invocation by the runtime.
+ /// single [`poll()`] invocation by the runtime.
///
/// Also note that yielding to competing tasks is not guaranteed: it is the
/// executor’s choice which task to run and the executor may choose to run the
/// current task again.
+ ///
+ /// [`poll()`]: crate::future::Future::poll
#[inline]
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn wake(self) {
@@ -250,8 +278,8 @@ impl Waker {
/// Wake up the task associated with this `Waker` without consuming the `Waker`.
///
- /// This is similar to `wake`, but may be slightly less efficient in the case
- /// where an owned `Waker` is available. This method should be preferred to
+ /// This is similar to [`wake()`](Self::wake), but may be slightly less efficient in
+ /// the case where an owned `Waker` is available. This method should be preferred to
/// calling `waker.clone().wake()`.
#[inline]
#[stable(feature = "futures_api", since = "1.36.0")]
@@ -263,7 +291,7 @@ impl Waker {
unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
}
- /// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
+ /// Returns `true` if this `Waker` and another `Waker` would awake the same task.
///
/// This function works on a best-effort basis, and may return false even
/// when the `Waker`s would awaken the same task. However, if this function
@@ -285,7 +313,8 @@ impl Waker {
#[inline]
#[must_use]
#[stable(feature = "futures_api", since = "1.36.0")]
- pub unsafe fn from_raw(waker: RawWaker) -> Waker {
+ #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ pub const unsafe fn from_raw(waker: RawWaker) -> Waker {
Waker { waker }
}
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 756f1a166..ba1cb6efa 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -29,6 +29,20 @@ const NANOS_PER_MICRO: u32 = 1_000;
const MILLIS_PER_SEC: u64 = 1_000;
const MICROS_PER_SEC: u64 = 1_000_000;
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+#[rustc_layout_scalar_valid_range_end(999_999_999)]
+struct Nanoseconds(u32);
+
+impl Default for Nanoseconds {
+ #[inline]
+ fn default() -> Self {
+ // SAFETY: 0 is within the valid range
+ unsafe { Nanoseconds(0) }
+ }
+}
+
/// A `Duration` type to represent a span of time, typically used for system
/// timeouts.
///
@@ -71,7 +85,7 @@ const MICROS_PER_SEC: u64 = 1_000_000;
#[cfg_attr(not(test), rustc_diagnostic_item = "Duration")]
pub struct Duration {
secs: u64,
- nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
+ nanos: Nanoseconds, // Always 0 <= nanos < NANOS_PER_SEC
}
impl Duration {
@@ -188,7 +202,8 @@ impl Duration {
None => panic!("overflow in Duration::new"),
};
let nanos = nanos % NANOS_PER_SEC;
- Duration { secs, nanos }
+ // SAFETY: nanos % NANOS_PER_SEC < NANOS_PER_SEC, therefore nanos is within the valid range
+ Duration { secs, nanos: unsafe { Nanoseconds(nanos) } }
}
/// Creates a new `Duration` from the specified number of whole seconds.
@@ -208,7 +223,7 @@ impl Duration {
#[inline]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
pub const fn from_secs(secs: u64) -> Duration {
- Duration { secs, nanos: 0 }
+ Duration::new(secs, 0)
}
/// Creates a new `Duration` from the specified number of milliseconds.
@@ -228,10 +243,7 @@ impl Duration {
#[inline]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
pub const fn from_millis(millis: u64) -> Duration {
- Duration {
- secs: millis / MILLIS_PER_SEC,
- nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI,
- }
+ Duration::new(millis / MILLIS_PER_SEC, ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI)
}
/// Creates a new `Duration` from the specified number of microseconds.
@@ -251,10 +263,7 @@ impl Duration {
#[inline]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
pub const fn from_micros(micros: u64) -> Duration {
- Duration {
- secs: micros / MICROS_PER_SEC,
- nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO,
- }
+ Duration::new(micros / MICROS_PER_SEC, ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO)
}
/// Creates a new `Duration` from the specified number of nanoseconds.
@@ -274,10 +283,7 @@ impl Duration {
#[inline]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
pub const fn from_nanos(nanos: u64) -> Duration {
- Duration {
- secs: nanos / (NANOS_PER_SEC as u64),
- nanos: (nanos % (NANOS_PER_SEC as u64)) as u32,
- }
+ Duration::new(nanos / (NANOS_PER_SEC as u64), (nanos % (NANOS_PER_SEC as u64)) as u32)
}
/// Returns true if this `Duration` spans no time.
@@ -301,7 +307,7 @@ impl Duration {
#[rustc_const_stable(feature = "duration_zero", since = "1.53.0")]
#[inline]
pub const fn is_zero(&self) -> bool {
- self.secs == 0 && self.nanos == 0
+ self.secs == 0 && self.nanos.0 == 0
}
/// Returns the number of _whole_ seconds contained by this `Duration`.
@@ -318,19 +324,11 @@ impl Duration {
/// assert_eq!(duration.as_secs(), 5);
/// ```
///
- /// To determine the total number of seconds represented by the `Duration`,
- /// use `as_secs` in combination with [`subsec_nanos`]:
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// let duration = Duration::new(5, 730023852);
- ///
- /// assert_eq!(5.730023852,
- /// duration.as_secs() as f64
- /// + duration.subsec_nanos() as f64 * 1e-9);
- /// ```
+ /// To determine the total number of seconds represented by the `Duration`
+ /// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`]
///
+ /// [`as_secs_f64`]: Duration::as_secs_f64
+ /// [`as_secs_f32`]: Duration::as_secs_f32
/// [`subsec_nanos`]: Duration::subsec_nanos
#[stable(feature = "duration", since = "1.3.0")]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
@@ -360,7 +358,7 @@ impl Duration {
#[must_use]
#[inline]
pub const fn subsec_millis(&self) -> u32 {
- self.nanos / NANOS_PER_MILLI
+ self.nanos.0 / NANOS_PER_MILLI
}
/// Returns the fractional part of this `Duration`, in whole microseconds.
@@ -383,7 +381,7 @@ impl Duration {
#[must_use]
#[inline]
pub const fn subsec_micros(&self) -> u32 {
- self.nanos / NANOS_PER_MICRO
+ self.nanos.0 / NANOS_PER_MICRO
}
/// Returns the fractional part of this `Duration`, in nanoseconds.
@@ -406,7 +404,7 @@ impl Duration {
#[must_use]
#[inline]
pub const fn subsec_nanos(&self) -> u32 {
- self.nanos
+ self.nanos.0
}
/// Returns the total number of whole milliseconds contained by this `Duration`.
@@ -424,7 +422,7 @@ impl Duration {
#[must_use]
#[inline]
pub const fn as_millis(&self) -> u128 {
- self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128
+ self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MILLI) as u128
}
/// Returns the total number of whole microseconds contained by this `Duration`.
@@ -442,7 +440,7 @@ impl Duration {
#[must_use]
#[inline]
pub const fn as_micros(&self) -> u128 {
- self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128
+ self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MICRO) as u128
}
/// Returns the total number of nanoseconds contained by this `Duration`.
@@ -460,7 +458,7 @@ impl Duration {
#[must_use]
#[inline]
pub const fn as_nanos(&self) -> u128 {
- self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128
+ self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos.0 as u128
}
/// Checked `Duration` addition. Computes `self + other`, returning [`None`]
@@ -483,7 +481,7 @@ impl Duration {
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
- let mut nanos = self.nanos + rhs.nanos;
+ let mut nanos = self.nanos.0 + rhs.nanos.0;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
if let Some(new_secs) = secs.checked_add(1) {
@@ -493,7 +491,7 @@ impl Duration {
}
}
debug_assert!(nanos < NANOS_PER_SEC);
- Some(Duration { secs, nanos })
+ Some(Duration::new(secs, nanos))
} else {
None
}
@@ -543,16 +541,16 @@ impl Duration {
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
- let nanos = if self.nanos >= rhs.nanos {
- self.nanos - rhs.nanos
+ let nanos = if self.nanos.0 >= rhs.nanos.0 {
+ self.nanos.0 - rhs.nanos.0
} else if let Some(sub_secs) = secs.checked_sub(1) {
secs = sub_secs;
- self.nanos + NANOS_PER_SEC - rhs.nanos
+ self.nanos.0 + NANOS_PER_SEC - rhs.nanos.0
} else {
return None;
};
debug_assert!(nanos < NANOS_PER_SEC);
- Some(Duration { secs, nanos })
+ Some(Duration::new(secs, nanos))
} else {
None
}
@@ -601,13 +599,13 @@ impl Duration {
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_mul(self, rhs: u32) -> Option<Duration> {
// Multiply nanoseconds as u64, because it cannot overflow that way.
- let total_nanos = self.nanos as u64 * rhs as u64;
+ let total_nanos = self.nanos.0 as u64 * rhs as u64;
let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
if let Some(s) = self.secs.checked_mul(rhs as u64) {
if let Some(secs) = s.checked_add(extra_secs) {
debug_assert!(nanos < NANOS_PER_SEC);
- return Some(Duration { secs, nanos });
+ return Some(Duration::new(secs, nanos));
}
}
None
@@ -661,9 +659,9 @@ impl Duration {
let secs = self.secs / (rhs as u64);
let carry = self.secs - secs * (rhs as u64);
let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
- let nanos = self.nanos / rhs + (extra_nanos as u32);
+ let nanos = self.nanos.0 / rhs + (extra_nanos as u32);
debug_assert!(nanos < NANOS_PER_SEC);
- Some(Duration { secs, nanos })
+ Some(Duration::new(secs, nanos))
} else {
None
}
@@ -685,7 +683,7 @@ impl Duration {
#[inline]
#[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn as_secs_f64(&self) -> f64 {
- (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
+ (self.secs as f64) + (self.nanos.0 as f64) / (NANOS_PER_SEC as f64)
}
/// Returns the number of seconds contained by this `Duration` as `f32`.
@@ -704,7 +702,7 @@ impl Duration {
#[inline]
#[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn as_secs_f32(&self) -> f32 {
- (self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32)
+ (self.secs as f32) + (self.nanos.0 as f32) / (NANOS_PER_SEC as f32)
}
/// Creates a new `Duration` from the specified number of seconds represented
@@ -995,13 +993,13 @@ macro_rules! sum_durations {
for entry in $iter {
total_secs =
total_secs.checked_add(entry.secs).expect("overflow in iter::sum over durations");
- total_nanos = match total_nanos.checked_add(entry.nanos as u64) {
+ total_nanos = match total_nanos.checked_add(entry.nanos.0 as u64) {
Some(n) => n,
None => {
total_secs = total_secs
.checked_add(total_nanos / NANOS_PER_SEC as u64)
.expect("overflow in iter::sum over durations");
- (total_nanos % NANOS_PER_SEC as u64) + entry.nanos as u64
+ (total_nanos % NANOS_PER_SEC as u64) + entry.nanos.0 as u64
}
};
}
@@ -1009,7 +1007,7 @@ macro_rules! sum_durations {
.checked_add(total_nanos / NANOS_PER_SEC as u64)
.expect("overflow in iter::sum over durations");
total_nanos = total_nanos % NANOS_PER_SEC as u64;
- Duration { secs: total_secs, nanos: total_nanos as u32 }
+ Duration::new(total_secs, total_nanos as u32)
}};
}
@@ -1045,7 +1043,7 @@ impl fmt::Debug for Duration {
/// to the formatter's `width`, if specified.
fn fmt_decimal(
f: &mut fmt::Formatter<'_>,
- mut integer_part: u64,
+ integer_part: u64,
mut fractional_part: u32,
mut divisor: u32,
prefix: &str,
@@ -1077,7 +1075,7 @@ impl fmt::Debug for Duration {
// normal floating point numbers. However, we only need to do work
// when rounding up. This happens if the first digit of the
// remaining ones is >= 5.
- if fractional_part > 0 && fractional_part >= divisor * 5 {
+ let integer_part = if fractional_part > 0 && fractional_part >= divisor * 5 {
// Round up the number contained in the buffer. We go through
// the buffer backwards and keep track of the carry.
let mut rev_pos = pos;
@@ -1101,9 +1099,18 @@ impl fmt::Debug for Duration {
// the whole buffer to '0's and need to increment the integer
// part.
if carry {
- integer_part += 1;
+ // If `integer_part == u64::MAX` and precision < 9, any
+ // carry of the overflow during rounding of the
+ // `fractional_part` into the `integer_part` will cause the
+ // `integer_part` itself to overflow. Avoid this by using an
+ // `Option<u64>`, with `None` representing `u64::MAX + 1`.
+ integer_part.checked_add(1)
+ } else {
+ Some(integer_part)
}
- }
+ } else {
+ Some(integer_part)
+ };
// Determine the end of the buffer: if precision is set, we just
// use as many digits from the buffer (capped to 9). If it isn't
@@ -1113,7 +1120,12 @@ impl fmt::Debug for Duration {
// This closure emits the formatted duration without emitting any
// padding (padding is calculated below).
let emit_without_padding = |f: &mut fmt::Formatter<'_>| {
- write!(f, "{}{}", prefix, integer_part)?;
+ if let Some(integer_part) = integer_part {
+ write!(f, "{}{}", prefix, integer_part)?;
+ } else {
+ // u64::MAX + 1 == 18446744073709551616
+ write!(f, "{}18446744073709551616", prefix)?;
+ }
// Write the decimal point and the fractional part (if any).
if end > 0 {
@@ -1143,12 +1155,17 @@ impl fmt::Debug for Duration {
// 2. The postfix: can be "µs" so we have to count UTF8 characters.
let mut actual_w = prefix.len() + postfix.chars().count();
// 3. The integer part:
- if let Some(log) = integer_part.checked_log10() {
- // integer_part is > 0, so has length log10(x)+1
- actual_w += 1 + log as usize;
+ if let Some(integer_part) = integer_part {
+ if let Some(log) = integer_part.checked_ilog10() {
+ // integer_part is > 0, so has length log10(x)+1
+ actual_w += 1 + log as usize;
+ } else {
+ // integer_part is 0, so has length 1.
+ actual_w += 1;
+ }
} else {
- // integer_part is 0, so has length 1.
- actual_w += 1;
+ // integer_part is u64::MAX + 1, so has length 20
+ actual_w += 20;
}
// 4. The fractional part (if any):
if end > 0 {
@@ -1174,27 +1191,27 @@ impl fmt::Debug for Duration {
let prefix = if f.sign_plus() { "+" } else { "" };
if self.secs > 0 {
- fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10, prefix, "s")
- } else if self.nanos >= NANOS_PER_MILLI {
+ fmt_decimal(f, self.secs, self.nanos.0, NANOS_PER_SEC / 10, prefix, "s")
+ } else if self.nanos.0 >= NANOS_PER_MILLI {
fmt_decimal(
f,
- (self.nanos / NANOS_PER_MILLI) as u64,
- self.nanos % NANOS_PER_MILLI,
+ (self.nanos.0 / NANOS_PER_MILLI) as u64,
+ self.nanos.0 % NANOS_PER_MILLI,
NANOS_PER_MILLI / 10,
prefix,
"ms",
)
- } else if self.nanos >= NANOS_PER_MICRO {
+ } else if self.nanos.0 >= NANOS_PER_MICRO {
fmt_decimal(
f,
- (self.nanos / NANOS_PER_MICRO) as u64,
- self.nanos % NANOS_PER_MICRO,
+ (self.nanos.0 / NANOS_PER_MICRO) as u64,
+ self.nanos.0 % NANOS_PER_MICRO,
NANOS_PER_MICRO / 10,
prefix,
"µs",
)
} else {
- fmt_decimal(f, self.nanos as u64, 0, 1, prefix, "ns")
+ fmt_decimal(f, self.nanos.0 as u64, 0, 1, prefix, "ns")
}
}
}
@@ -1208,7 +1225,6 @@ impl fmt::Debug for Duration {
/// # Example
///
/// ```
-/// #![feature(duration_checked_float)]
/// use std::time::Duration;
///
/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
@@ -1216,33 +1232,33 @@ impl fmt::Debug for Duration {
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
-#[unstable(feature = "duration_checked_float", issue = "83400")]
-pub struct FromFloatSecsError {
- kind: FromFloatSecsErrorKind,
+#[stable(feature = "duration_checked_float", since = "1.66.0")]
+pub struct TryFromFloatSecsError {
+ kind: TryFromFloatSecsErrorKind,
}
-impl FromFloatSecsError {
+impl TryFromFloatSecsError {
const fn description(&self) -> &'static str {
match self.kind {
- FromFloatSecsErrorKind::Negative => {
+ TryFromFloatSecsErrorKind::Negative => {
"can not convert float seconds to Duration: value is negative"
}
- FromFloatSecsErrorKind::OverflowOrNan => {
+ TryFromFloatSecsErrorKind::OverflowOrNan => {
"can not convert float seconds to Duration: value is either too big or NaN"
}
}
}
}
-#[unstable(feature = "duration_checked_float", issue = "83400")]
-impl fmt::Display for FromFloatSecsError {
+#[stable(feature = "duration_checked_float", since = "1.66.0")]
+impl fmt::Display for TryFromFloatSecsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.description().fmt(f)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
-enum FromFloatSecsErrorKind {
+enum TryFromFloatSecsErrorKind {
// Value is negative.
Negative,
// Value is either too big to be represented as `Duration` or `NaN`.
@@ -1262,8 +1278,8 @@ macro_rules! try_from_secs {
const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1;
const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1;
- if $secs.is_sign_negative() {
- return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::Negative });
+ if $secs < 0.0 {
+ return Err(TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind::Negative });
}
let bits = $secs.to_bits();
@@ -1288,7 +1304,7 @@ macro_rules! try_from_secs {
let rem_msb = nanos_tmp & rem_msb_mask == 0;
let add_ns = !(rem_msb || (is_even && is_tie));
- // f32 does not have enough presicion to trigger the second branch
+ // f32 does not have enough precision to trigger the second branch
// since it can not represent numbers between 0.999_999_940_395 and 1.0.
let nanos = nanos + add_ns as u32;
if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { (0, nanos) } else { (1, 0) }
@@ -1307,9 +1323,9 @@ macro_rules! try_from_secs {
let rem_msb = nanos_tmp & rem_msb_mask == 0;
let add_ns = !(rem_msb || (is_even && is_tie));
- // f32 does not have enough presicion to trigger the second branch.
+ // f32 does not have enough precision to trigger the second branch.
// For example, it can not represent numbers between 1.999_999_880...
- // and 2.0. Bigger values result in even smaller presicion of the
+ // and 2.0. Bigger values result in even smaller precision of the
// fractional part.
let nanos = nanos + add_ns as u32;
if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) {
@@ -1322,10 +1338,10 @@ macro_rules! try_from_secs {
let secs = u64::from(mant) << (exp - $mant_bits);
(secs, 0)
} else {
- return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::OverflowOrNan });
+ return Err(TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind::OverflowOrNan });
};
- Ok(Duration { secs, nanos })
+ Ok(Duration::new(secs, nanos))
}};
}
@@ -1338,8 +1354,6 @@ impl Duration {
///
/// # Examples
/// ```
- /// #![feature(duration_checked_float)]
- ///
/// use std::time::Duration;
///
/// let res = Duration::try_from_secs_f32(0.0);
@@ -1387,9 +1401,10 @@ impl Duration {
/// let res = Duration::try_from_secs_f32(val);
/// assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
/// ```
- #[unstable(feature = "duration_checked_float", issue = "83400")]
+ #[stable(feature = "duration_checked_float", since = "1.66.0")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
#[inline]
- pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromFloatSecsError> {
+ pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, TryFromFloatSecsError> {
try_from_secs!(
secs = secs,
mantissa_bits = 23,
@@ -1408,8 +1423,6 @@ impl Duration {
///
/// # Examples
/// ```
- /// #![feature(duration_checked_float)]
- ///
/// use std::time::Duration;
///
/// let res = Duration::try_from_secs_f64(0.0);
@@ -1465,9 +1478,10 @@ impl Duration {
/// let res = Duration::try_from_secs_f64(val);
/// assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
/// ```
- #[unstable(feature = "duration_checked_float", issue = "83400")]
+ #[stable(feature = "duration_checked_float", since = "1.66.0")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
#[inline]
- pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromFloatSecsError> {
+ pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, TryFromFloatSecsError> {
try_from_secs!(
secs = secs,
mantissa_bits = 52,
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index d189e6400..fc91fe468 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -93,7 +93,8 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
- impl<$($T:Default),+> Default for ($($T,)+) {
+ #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+ impl<$($T: ~const Default),+> const Default for ($($T,)+) {
#[inline]
fn default() -> ($($T,)+) {
($({ let x: $T = Default::default(); x},)+)
@@ -107,7 +108,7 @@ macro_rules! tuple_impls {
// Otherwise, it hides the docs entirely.
macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
- #[cfg_attr(not(bootstrap), doc(fake_variadic))]
+ #[doc(fake_variadic)]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
diff --git a/library/core/src/unicode/printable.rs b/library/core/src/unicode/printable.rs
index 31cf88a41..ffb18a5ba 100644
--- a/library/core/src/unicode/printable.rs
+++ b/library/core/src/unicode/printable.rs
@@ -54,7 +54,7 @@ pub(crate) fn is_printable(x: char) -> bool {
if 0x2a6e0 <= x && x < 0x2a700 {
return false;
}
- if 0x2b739 <= x && x < 0x2b740 {
+ if 0x2b73a <= x && x < 0x2b740 {
return false;
}
if 0x2b81e <= x && x < 0x2b820 {
@@ -69,7 +69,10 @@ pub(crate) fn is_printable(x: char) -> bool {
if 0x2fa1e <= x && x < 0x30000 {
return false;
}
- if 0x3134b <= x && x < 0xe0100 {
+ if 0x3134b <= x && x < 0x31350 {
+ return false;
+ }
+ if 0x323b0 <= x && x < 0xe0100 {
return false;
}
if 0xe01f0 <= x && x < 0x110000 {
@@ -92,7 +95,7 @@ const SINGLETONS0U: &[(u8, u8)] = &[
(0x0b, 25),
(0x0c, 26),
(0x0d, 16),
- (0x0e, 13),
+ (0x0e, 12),
(0x0f, 4),
(0x10, 3),
(0x12, 18),
@@ -142,24 +145,24 @@ const SINGLETONS0L: &[u8] = &[
0xe4, 0xe5, 0xf0, 0x0d, 0x11, 0x45, 0x49, 0x64,
0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5,
0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6,
- 0xbe, 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb,
- 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49,
- 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e,
- 0x8f, 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7,
- 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7,
- 0xfe, 0xff, 0x80, 0x6d, 0x71, 0xde, 0xdf, 0x0e,
- 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e,
- 0xae, 0xaf, 0x7f, 0xbb, 0xbc, 0x16, 0x17, 0x1e,
- 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c,
- 0x5e, 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc,
- 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75,
- 0x96, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf,
- 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98,
- 0x30, 0x8f, 0x1f, 0xd2, 0xd4, 0xce, 0xff, 0x4e,
- 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
- 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f,
- 0x42, 0x45, 0x90, 0x91, 0x53, 0x67, 0x75, 0xc8,
- 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff,
+ 0xbe, 0xbf, 0xc5, 0xc7, 0xcf, 0xda, 0xdb, 0x48,
+ 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e,
+ 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f,
+ 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7,
+ 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe,
+ 0xff, 0x80, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x1f,
+ 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae,
+ 0xaf, 0x7f, 0xbb, 0xbc, 0x16, 0x17, 0x1e, 0x1f,
+ 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e,
+ 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0,
+ 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96,
+ 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, 0xc7,
+ 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30,
+ 0x8f, 0x1f, 0xd2, 0xd4, 0xce, 0xff, 0x4e, 0x4f,
+ 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f,
+ 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42,
+ 0x45, 0x90, 0x91, 0x53, 0x67, 0x75, 0xc8, 0xc9,
+ 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff,
];
#[rustfmt::skip]
const SINGLETONS1U: &[(u8, u8)] = &[
@@ -184,10 +187,12 @@ const SINGLETONS1U: &[(u8, u8)] = &[
(0x19, 13),
(0x1c, 5),
(0x1d, 8),
+ (0x1f, 1),
(0x24, 1),
(0x6a, 4),
(0x6b, 2),
(0xaf, 3),
+ (0xb1, 2),
(0xbc, 2),
(0xcf, 2),
(0xd1, 2),
@@ -203,7 +208,7 @@ const SINGLETONS1U: &[(u8, u8)] = &[
(0xee, 32),
(0xf0, 4),
(0xf8, 2),
- (0xfa, 2),
+ (0xfa, 3),
(0xfb, 1),
];
#[rustfmt::skip]
@@ -220,18 +225,19 @@ const SINGLETONS1L: &[u8] = &[
0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8,
0xa9, 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8,
0x07, 0x0a, 0x3b, 0x3e, 0x66, 0x69, 0x8f, 0x92,
- 0x6f, 0x5f, 0xbf, 0xee, 0xef, 0x5a, 0x62, 0xf4,
- 0xfc, 0xff, 0x9a, 0x9b, 0x2e, 0x2f, 0x27, 0x28,
- 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8,
- 0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15,
- 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc,
- 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e,
- 0x3f, 0xe7, 0xec, 0xef, 0xff, 0xc5, 0xc6, 0x04,
- 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a,
- 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, 0x58,
- 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, 0x6b,
- 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf,
- 0xb0, 0xc0, 0xd0, 0xae, 0xaf, 0x6e, 0x6f, 0x93,
+ 0x11, 0x6f, 0x5f, 0xbf, 0xee, 0xef, 0x5a, 0x62,
+ 0xf4, 0xfc, 0xff, 0x53, 0x54, 0x9a, 0x9b, 0x2e,
+ 0x2f, 0x27, 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3,
+ 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, 0xc4, 0x06,
+ 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51,
+ 0xa6, 0xa7, 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a,
+ 0x22, 0x25, 0x3e, 0x3f, 0xe7, 0xec, 0xef, 0xff,
+ 0xc5, 0xc6, 0x04, 0x20, 0x23, 0x25, 0x26, 0x28,
+ 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53,
+ 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63,
+ 0x65, 0x66, 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a,
+ 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0xae, 0xaf,
+ 0x6e, 0x6f, 0xbe, 0x93,
];
#[rustfmt::skip]
const NORMAL0: &[u8] = &[
@@ -272,7 +278,7 @@ const NORMAL0: &[u8] = &[
0x1b, 0x07,
0x57, 0x07,
0x02, 0x06,
- 0x16, 0x0d,
+ 0x17, 0x0c,
0x50, 0x04,
0x43, 0x03,
0x2d, 0x03,
@@ -424,8 +430,8 @@ const NORMAL1: &[u8] = &[
0x33, 0x07,
0x2e, 0x08,
0x0a, 0x81, 0x26,
- 0x52, 0x4e,
- 0x28, 0x08,
+ 0x52, 0x4b,
+ 0x2b, 0x08,
0x2a, 0x16,
0x1a, 0x26,
0x1c, 0x14,
@@ -438,7 +444,7 @@ const NORMAL1: &[u8] = &[
0x48, 0x08,
0x27, 0x09,
0x75, 0x0b,
- 0x3f, 0x41,
+ 0x42, 0x3e,
0x2a, 0x06,
0x3b, 0x05,
0x0a, 0x06,
@@ -464,7 +470,8 @@ const NORMAL1: &[u8] = &[
0x45, 0x1b,
0x48, 0x08,
0x53, 0x0d,
- 0x49, 0x81, 0x07,
+ 0x49, 0x07,
+ 0x0a, 0x80, 0xf6,
0x46, 0x0a,
0x1d, 0x03,
0x47, 0x49,
@@ -473,14 +480,17 @@ const NORMAL1: &[u8] = &[
0x0a, 0x06,
0x39, 0x07,
0x0a, 0x81, 0x36,
- 0x19, 0x80, 0xb7,
+ 0x19, 0x07,
+ 0x3b, 0x03,
+ 0x1c, 0x56,
0x01, 0x0f,
0x32, 0x0d,
0x83, 0x9b, 0x66,
0x75, 0x0b,
0x80, 0xc4, 0x8a, 0x4c,
0x63, 0x0d,
- 0x84, 0x2f, 0x8f, 0xd1,
+ 0x84, 0x30, 0x10,
+ 0x16, 0x8f, 0xaa,
0x82, 0x47, 0xa1, 0xb9,
0x82, 0x39, 0x07,
0x2a, 0x04,
@@ -498,8 +508,9 @@ const NORMAL1: &[u8] = &[
0x97, 0xf8, 0x08,
0x84, 0xd6, 0x2a,
0x09, 0xa2, 0xe7,
- 0x81, 0x33, 0x2d,
- 0x03, 0x11,
+ 0x81, 0x33, 0x0f,
+ 0x01, 0x1d,
+ 0x06, 0x0e,
0x04, 0x08,
0x81, 0x8c, 0x89, 0x04,
0x6b, 0x05,
@@ -511,21 +522,26 @@ const NORMAL1: &[u8] = &[
0x80, 0xf6, 0x0a,
0x73, 0x08,
0x70, 0x15,
- 0x46, 0x80, 0x9a,
+ 0x46, 0x7a,
+ 0x14, 0x0c,
0x14, 0x0c,
0x57, 0x09,
0x19, 0x80, 0x87,
0x81, 0x47, 0x03,
0x85, 0x42, 0x0f,
0x15, 0x84, 0x50,
- 0x1f, 0x80, 0xe1,
- 0x2b, 0x80, 0xd5,
+ 0x1f, 0x06,
+ 0x06, 0x80, 0xd5,
+ 0x2b, 0x05,
+ 0x3e, 0x21,
+ 0x01, 0x70,
0x2d, 0x03,
0x1a, 0x04,
0x02, 0x81, 0x40,
0x1f, 0x11,
0x3a, 0x05,
- 0x01, 0x84, 0xe0,
+ 0x01, 0x81, 0xd0,
+ 0x2a, 0x82, 0xe6,
0x80, 0xf7, 0x29,
0x4c, 0x04,
0x0a, 0x04,
@@ -546,11 +562,11 @@ const NORMAL1: &[u8] = &[
0x09, 0x07,
0x02, 0x0e,
0x06, 0x80, 0x9a,
- 0x83, 0xd8, 0x05,
- 0x10, 0x03,
+ 0x83, 0xd8, 0x04,
+ 0x11, 0x03,
0x0d, 0x03,
- 0x74, 0x0c,
- 0x59, 0x07,
+ 0x77, 0x04,
+ 0x5f, 0x06,
0x0c, 0x04,
0x01, 0x0f,
0x0c, 0x04,
@@ -559,15 +575,12 @@ const NORMAL1: &[u8] = &[
0x28, 0x08,
0x22, 0x4e,
0x81, 0x54, 0x0c,
- 0x15, 0x03,
- 0x05, 0x03,
- 0x07, 0x09,
0x1d, 0x03,
- 0x0b, 0x05,
- 0x06, 0x0a,
- 0x0a, 0x06,
- 0x08, 0x08,
- 0x07, 0x09,
+ 0x09, 0x07,
+ 0x36, 0x08,
+ 0x0e, 0x04,
+ 0x09, 0x07,
+ 0x09, 0x07,
0x80, 0xcb, 0x25,
0x0a, 0x84, 0x06,
];
diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs
index d2073f86c..bd69ca520 100644
--- a/library/core/src/unicode/unicode_data.rs
+++ b/library/core/src/unicode/unicode_data.rs
@@ -1,7 +1,8 @@
///! This file is generated by src/tools/unicode-table-generator; do not edit manually!
+#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
#[inline(always)]
-fn bitset_search<
+const fn bitset_search<
const N: usize,
const CHUNK_SIZE: usize,
const N1: usize,
@@ -17,14 +18,18 @@ fn bitset_search<
let bucket_idx = (needle / 64) as usize;
let chunk_map_idx = bucket_idx / CHUNK_SIZE;
let chunk_piece = bucket_idx % CHUNK_SIZE;
- let chunk_idx = if let Some(&v) = chunk_idx_map.get(chunk_map_idx) {
- v
+ // FIXME: const-hack: Revert to `slice::get` after `const_slice_index`
+ // feature stabilizes.
+ let chunk_idx = if chunk_map_idx < chunk_idx_map.len() {
+ chunk_idx_map[chunk_map_idx]
} else {
return false;
};
let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize;
- let word = if let Some(word) = bitset_canonical.get(idx) {
- *word
+ // FIXME: const-hack: Revert to `slice::get` after `const_slice_index`
+ // feature stabilizes.
+ let word = if idx < bitset_canonical.len() {
+ bitset_canonical[idx]
} else {
let (real_idx, mapping) = bitset_canonicalized[idx - bitset_canonical.len()];
let mut word = bitset_canonical[real_idx as usize];
@@ -94,21 +99,21 @@ fn skip_search<const SOR: usize, const OFFSETS: usize>(
offset_idx % 2 == 1
}
-pub const UNICODE_VERSION: (u8, u8, u8) = (14, 0, 0);
+pub const UNICODE_VERSION: (u8, u8, u8) = (15, 0, 0);
#[rustfmt::skip]
pub mod alphabetic {
- static SHORT_OFFSET_RUNS: [u32; 51] = [
- 706, 33559113, 876615277, 956309270, 1166025910, 1314925568, 1319120901, 1398813696,
- 1449151936, 1451271309, 1455465997, 1463867300, 1652619520, 1663105646, 1665203518,
- 1711342208, 1797326647, 1891700352, 2044795904, 2397118176, 2485199770, 2495688592,
- 2506175535, 2512471040, 2514568775, 2516674560, 2518772281, 2520870464, 2552334328,
- 2583792854, 2587996144, 2594287907, 2608968444, 2621553664, 2623656960, 2644629158,
- 2722225920, 2770461328, 2808211424, 2816601600, 2850156848, 2988572672, 3001198304,
- 3003299641, 3007499938, 3015896033, 3020093440, 3022191134, 3024289792, 3026391883,
- 3029603147,
+ static SHORT_OFFSET_RUNS: [u32; 53] = [
+ 706, 33559113, 872420973, 952114966, 1161831606, 1310731264, 1314926597, 1394619392,
+ 1444957632, 1447077005, 1451271693, 1459672996, 1648425216, 1658911342, 1661009214,
+ 1707147904, 1793132343, 1887506048, 2040601600, 2392923872, 2481005466, 2504077200,
+ 2514564144, 2520859648, 2527151687, 2529257472, 2531355193, 2533453376, 2564917240,
+ 2596375766, 2600579056, 2606870819, 2621551356, 2642525184, 2644628480, 2665600678,
+ 2743197440, 2791432848, 2841765072, 2850154464, 2854350336, 2887905584, 3026321408,
+ 3038947040, 3041048378, 3045248674, 3053644769, 3057842176, 3059939870, 3062038528,
+ 3064140619, 3066241968, 3071550384,
];
- static OFFSETS: [u8; 1445] = [
+ static OFFSETS: [u8; 1465] = [
65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 42,
5, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, 39,
14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, 10,
@@ -118,50 +123,51 @@ pub mod alphabetic {
2, 1, 2, 4, 5, 4, 2, 2, 2, 4, 1, 7, 4, 1, 1, 17, 6, 11, 3, 1, 9, 1, 3, 1, 22, 1, 7, 1, 2, 1,
5, 3, 9, 1, 3, 1, 2, 3, 1, 15, 4, 21, 4, 4, 3, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2,
2, 2, 2, 9, 2, 4, 2, 1, 5, 13, 1, 16, 2, 1, 6, 3, 3, 1, 4, 3, 2, 1, 1, 1, 2, 3, 2, 3, 3, 3,
- 12, 4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 4, 1, 8, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8, 2,
- 1, 3, 2, 1, 2, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 6, 2, 1, 4,
- 13, 2, 13, 13, 1, 3, 1, 41, 2, 8, 1, 3, 1, 3, 1, 1, 5, 4, 7, 5, 22, 6, 1, 3, 1, 18, 3, 24,
- 1, 9, 1, 1, 2, 7, 8, 6, 1, 1, 1, 8, 18, 2, 13, 58, 5, 7, 6, 1, 51, 2, 1, 1, 1, 5, 1, 24, 1,
- 1, 1, 19, 1, 3, 2, 5, 1, 1, 6, 1, 14, 4, 32, 1, 63, 8, 1, 36, 4, 17, 6, 16, 1, 36, 67, 55,
- 1, 1, 2, 5, 16, 64, 10, 4, 2, 38, 1, 1, 5, 1, 2, 43, 1, 0, 1, 4, 2, 7, 1, 1, 1, 4, 2, 41, 1,
- 4, 2, 33, 1, 4, 2, 7, 1, 1, 1, 4, 2, 15, 1, 57, 1, 4, 2, 67, 37, 16, 16, 86, 2, 6, 3, 0, 2,
- 17, 1, 26, 5, 75, 3, 11, 7, 20, 11, 21, 12, 20, 12, 13, 1, 3, 1, 2, 12, 52, 2, 19, 14, 1, 4,
- 1, 67, 89, 7, 43, 5, 70, 10, 31, 1, 12, 4, 9, 23, 30, 2, 5, 11, 44, 4, 26, 54, 28, 4, 63, 2,
- 20, 50, 1, 23, 2, 11, 3, 49, 52, 1, 15, 1, 8, 51, 42, 2, 4, 10, 44, 1, 11, 14, 55, 22, 3,
- 10, 36, 2, 9, 7, 43, 2, 3, 41, 4, 1, 6, 1, 2, 3, 1, 5, 192, 39, 14, 11, 0, 2, 6, 2, 38, 2,
- 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, 5, 3, 1,
- 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, 1, 11, 2,
- 4, 5, 5, 4, 1, 17, 41, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 2, 56, 7, 1, 16, 23,
- 9, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 32, 47, 1, 0, 3, 25, 9, 7, 5, 2, 5, 4,
- 86, 6, 3, 1, 90, 1, 4, 5, 43, 1, 94, 17, 32, 48, 16, 0, 0, 64, 0, 67, 46, 2, 0, 3, 16, 10,
- 2, 20, 47, 5, 8, 3, 113, 39, 9, 2, 103, 2, 64, 5, 2, 1, 1, 1, 5, 24, 20, 1, 33, 24, 52, 12,
- 68, 1, 1, 44, 6, 3, 1, 1, 3, 10, 33, 5, 35, 13, 29, 3, 51, 1, 12, 15, 1, 16, 16, 10, 5, 1,
- 55, 9, 14, 18, 23, 3, 69, 1, 1, 1, 1, 24, 3, 2, 16, 2, 4, 11, 6, 2, 6, 2, 6, 9, 7, 1, 7, 1,
- 43, 1, 14, 6, 123, 21, 0, 12, 23, 4, 49, 0, 0, 2, 106, 38, 7, 12, 5, 5, 12, 1, 13, 1, 5, 1,
- 1, 1, 2, 1, 2, 1, 108, 33, 0, 18, 64, 2, 54, 40, 12, 116, 5, 1, 135, 36, 26, 6, 26, 11, 89,
- 3, 6, 2, 6, 2, 6, 2, 3, 35, 12, 1, 26, 1, 19, 1, 2, 1, 15, 2, 14, 34, 123, 69, 53, 0, 29, 3,
+ 12, 4, 5, 3, 3, 1, 3, 3, 1, 6, 1, 40, 13, 1, 3, 1, 23, 1, 16, 3, 8, 1, 3, 1, 3, 8, 2, 1, 3,
+ 2, 1, 2, 4, 28, 4, 1, 8, 1, 3, 1, 23, 1, 10, 1, 5, 3, 8, 1, 3, 1, 3, 8, 2, 6, 2, 1, 4, 13,
+ 3, 12, 13, 1, 3, 1, 41, 2, 8, 1, 3, 1, 3, 1, 1, 5, 4, 7, 5, 22, 6, 1, 3, 1, 18, 3, 24, 1, 9,
+ 1, 1, 2, 7, 8, 6, 1, 1, 1, 8, 18, 2, 13, 58, 5, 7, 6, 1, 51, 2, 1, 1, 1, 5, 1, 24, 1, 1, 1,
+ 19, 1, 3, 2, 5, 1, 1, 6, 1, 14, 4, 32, 1, 63, 8, 1, 36, 4, 19, 4, 16, 1, 36, 67, 55, 1, 1,
+ 2, 5, 16, 64, 10, 4, 2, 38, 1, 1, 5, 1, 2, 43, 1, 0, 1, 4, 2, 7, 1, 1, 1, 4, 2, 41, 1, 4, 2,
+ 33, 1, 4, 2, 7, 1, 1, 1, 4, 2, 15, 1, 57, 1, 4, 2, 67, 37, 16, 16, 86, 2, 6, 3, 0, 2, 17, 1,
+ 26, 5, 75, 3, 11, 7, 20, 11, 21, 12, 20, 12, 13, 1, 3, 1, 2, 12, 52, 2, 19, 14, 1, 4, 1, 67,
+ 89, 7, 43, 5, 70, 10, 31, 1, 12, 4, 9, 23, 30, 2, 5, 11, 44, 4, 26, 54, 28, 4, 63, 2, 20,
+ 50, 1, 23, 2, 11, 3, 49, 52, 1, 15, 1, 8, 51, 42, 2, 4, 10, 44, 1, 11, 14, 55, 22, 3, 10,
+ 36, 2, 9, 7, 43, 2, 3, 41, 4, 1, 6, 1, 2, 3, 1, 5, 192, 39, 14, 11, 0, 2, 6, 2, 38, 2, 6, 2,
+ 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13, 5, 3, 1, 7,
+ 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4, 1, 11, 2, 4,
+ 5, 5, 4, 1, 17, 41, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1, 2, 56, 7, 1, 16, 23, 9,
+ 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 32, 47, 1, 0, 3, 25, 9, 7, 5, 2, 5, 4, 86,
+ 6, 3, 1, 90, 1, 4, 5, 43, 1, 94, 17, 32, 48, 16, 0, 0, 64, 0, 67, 46, 2, 0, 3, 16, 10, 2,
+ 20, 47, 5, 8, 3, 113, 39, 9, 2, 103, 2, 64, 5, 2, 1, 1, 1, 5, 24, 20, 1, 33, 24, 52, 12, 68,
+ 1, 1, 44, 6, 3, 1, 1, 3, 10, 33, 5, 35, 13, 29, 3, 51, 1, 12, 15, 1, 16, 16, 10, 5, 1, 55,
+ 9, 14, 18, 23, 3, 69, 1, 1, 1, 1, 24, 3, 2, 16, 2, 4, 11, 6, 2, 6, 2, 6, 9, 7, 1, 7, 1, 43,
+ 1, 14, 6, 123, 21, 0, 12, 23, 4, 49, 0, 0, 2, 106, 38, 7, 12, 5, 5, 12, 1, 13, 1, 5, 1, 1,
+ 1, 2, 1, 2, 1, 108, 33, 0, 18, 64, 2, 54, 40, 12, 116, 5, 1, 135, 36, 26, 6, 26, 11, 89, 3,
+ 6, 2, 6, 2, 6, 2, 3, 35, 12, 1, 26, 1, 19, 1, 2, 1, 15, 2, 14, 34, 123, 69, 53, 0, 29, 3,
49, 47, 32, 13, 30, 5, 43, 5, 30, 2, 36, 4, 8, 1, 5, 42, 158, 18, 36, 4, 36, 4, 40, 8, 52,
12, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1, 7, 1, 2, 67, 0, 9, 22, 10, 8, 24, 6, 1, 42, 1,
9, 69, 6, 2, 1, 1, 44, 1, 2, 3, 1, 2, 23, 10, 23, 9, 31, 65, 19, 1, 2, 10, 22, 10, 26, 70,
56, 6, 2, 64, 4, 1, 2, 5, 8, 1, 3, 1, 29, 42, 29, 3, 29, 35, 8, 1, 28, 27, 54, 10, 22, 10,
19, 13, 18, 110, 73, 55, 51, 13, 51, 13, 40, 0, 42, 1, 2, 3, 2, 78, 29, 10, 1, 8, 22, 42,
- 18, 46, 21, 27, 23, 9, 70, 43, 5, 12, 55, 9, 1, 13, 25, 23, 51, 17, 4, 8, 35, 3, 1, 9, 64,
- 1, 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6, 1, 65, 7, 1, 1, 1, 4, 1, 15, 1, 10, 7, 57,
+ 18, 46, 21, 27, 23, 9, 70, 43, 5, 10, 57, 9, 1, 13, 25, 23, 51, 17, 4, 8, 35, 3, 1, 9, 64,
+ 1, 4, 9, 2, 10, 1, 1, 1, 35, 18, 1, 34, 2, 1, 6, 4, 62, 7, 1, 1, 1, 4, 1, 15, 1, 10, 7, 57,
23, 4, 1, 8, 2, 2, 2, 22, 1, 7, 1, 2, 1, 5, 3, 8, 2, 2, 2, 2, 3, 1, 6, 1, 5, 7, 156, 66, 1,
3, 1, 4, 20, 3, 30, 66, 2, 2, 1, 1, 184, 54, 2, 7, 25, 6, 34, 63, 1, 1, 3, 1, 59, 54, 2, 1,
71, 27, 2, 14, 21, 7, 185, 57, 103, 64, 31, 8, 2, 1, 2, 8, 1, 2, 1, 30, 1, 2, 2, 2, 2, 4,
93, 8, 2, 46, 2, 6, 1, 1, 1, 2, 27, 51, 2, 10, 17, 72, 5, 1, 18, 73, 0, 9, 1, 45, 1, 7, 1,
1, 49, 30, 2, 22, 1, 14, 73, 7, 1, 2, 1, 44, 3, 1, 1, 2, 1, 3, 1, 1, 2, 2, 24, 6, 1, 2, 1,
- 37, 1, 2, 1, 4, 1, 1, 0, 23, 185, 1, 79, 0, 102, 111, 17, 196, 0, 97, 15, 0, 0, 0, 0, 0, 7,
- 31, 17, 79, 17, 30, 18, 48, 16, 4, 31, 21, 5, 19, 0, 64, 128, 75, 4, 57, 7, 17, 64, 2, 1, 1,
- 12, 2, 14, 0, 8, 0, 42, 9, 0, 4, 1, 7, 1, 2, 1, 0, 45, 3, 17, 4, 8, 0, 0, 107, 5, 13, 3, 9,
- 7, 10, 4, 1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1,
- 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1,
- 25, 1, 31, 1, 25, 1, 8, 0, 31, 225, 7, 1, 17, 2, 7, 1, 2, 1, 5, 213, 45, 10, 7, 16, 1, 0,
- 30, 18, 44, 0, 7, 1, 4, 1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2,
- 1, 1, 10, 1, 4, 1, 1, 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 2, 1, 1, 2, 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26,
- 6, 26, 6, 26, 0, 0, 32, 0, 7, 222, 2, 0, 14, 0, 0, 0, 0, 0, 0,
+ 37, 1, 2, 1, 4, 1, 1, 0, 23, 9, 17, 1, 41, 3, 3, 111, 1, 79, 0, 102, 111, 17, 196, 0, 97,
+ 15, 0, 17, 6, 0, 0, 0, 0, 7, 31, 17, 79, 17, 30, 18, 48, 16, 4, 31, 21, 5, 19, 0, 64, 128,
+ 75, 4, 57, 7, 17, 64, 2, 1, 1, 12, 2, 14, 0, 8, 0, 42, 9, 0, 4, 1, 7, 1, 2, 1, 0, 15, 1, 29,
+ 3, 2, 1, 14, 4, 8, 0, 0, 107, 5, 13, 3, 9, 7, 10, 4, 1, 0, 85, 1, 71, 1, 2, 2, 1, 2, 2, 2,
+ 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2, 25,
+ 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 31, 6, 6, 213, 7, 1,
+ 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 112, 45, 10, 7, 16, 1, 0, 30, 18, 44, 0, 28, 0, 7, 1, 4,
+ 1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1,
+ 1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2,
+ 4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32,
+ 0, 6, 222, 2, 0, 14, 0, 0, 0, 0, 0, 5, 0, 0,
];
pub fn lookup(c: char) -> bool {
super::skip_search(
@@ -177,11 +183,11 @@ pub mod case_ignorable {
static SHORT_OFFSET_RUNS: [u32; 35] = [
688, 44045149, 572528402, 576724925, 807414908, 878718981, 903913493, 929080568, 933275148,
937491230, 1138818560, 1147208189, 1210124160, 1222707713, 1235291428, 1260457643,
- 1264654383, 1491147067, 1499536432, 1558257395, 1621177392, 1625385712, 1629581135,
- 1642180592, 1658961053, 1671548672, 1679937895, 1688328704, 1709301760, 1734467888,
- 1755439790, 1759635664, 1768027131, 1777205249, 1782514160,
+ 1264654383, 1499535675, 1507925040, 1566646003, 1629566000, 1650551536, 1658941263,
+ 1671540720, 1688321181, 1700908800, 1709298023, 1717688832, 1738661888, 1763828398,
+ 1797383403, 1805773008, 1809970171, 1819148289, 1824457200,
];
- static OFFSETS: [u8; 855] = [
+ static OFFSETS: [u8; 875] = [
39, 1, 6, 1, 11, 1, 35, 1, 1, 1, 71, 1, 4, 1, 1, 1, 4, 1, 2, 2, 0, 192, 4, 2, 4, 1, 9, 2,
1, 1, 251, 7, 207, 1, 5, 1, 49, 45, 1, 1, 1, 2, 1, 2, 1, 1, 44, 1, 11, 6, 10, 11, 1, 1, 35,
1, 10, 21, 16, 1, 101, 8, 1, 10, 1, 4, 33, 1, 1, 1, 30, 27, 91, 11, 58, 11, 4, 1, 2, 1, 24,
@@ -190,7 +196,7 @@ pub mod case_ignorable {
57, 1, 4, 5, 1, 2, 4, 1, 20, 2, 22, 6, 1, 1, 58, 1, 2, 1, 1, 4, 8, 1, 7, 2, 11, 2, 30, 1,
61, 1, 12, 1, 50, 1, 3, 1, 55, 1, 1, 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 6, 1,
5, 2, 20, 2, 28, 2, 57, 2, 4, 4, 8, 1, 20, 2, 29, 1, 72, 1, 7, 3, 1, 1, 90, 1, 2, 7, 11, 9,
- 98, 1, 2, 9, 9, 1, 1, 6, 74, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1,
+ 98, 1, 2, 9, 9, 1, 1, 7, 73, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1,
102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 94, 1, 0, 3, 0, 3,
29, 2, 30, 2, 30, 2, 64, 2, 1, 7, 8, 1, 2, 11, 3, 1, 5, 1, 45, 5, 51, 1, 65, 2, 34, 1, 118,
3, 4, 2, 9, 1, 6, 3, 219, 2, 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 39, 1, 8, 31,
@@ -204,15 +210,16 @@ pub mod case_ignorable {
1, 1, 27, 1, 14, 2, 5, 2, 1, 1, 100, 5, 9, 3, 121, 1, 2, 1, 4, 1, 0, 1, 147, 17, 0, 16, 3,
1, 12, 16, 34, 1, 2, 1, 169, 1, 7, 1, 6, 1, 11, 1, 35, 1, 1, 1, 47, 1, 45, 2, 67, 1, 21, 3,
0, 1, 226, 1, 149, 5, 0, 6, 1, 42, 1, 9, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 0, 2,
- 153, 11, 49, 4, 123, 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 2, 1, 4, 1, 10, 1, 50, 3,
- 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, 1, 160, 1, 3, 8, 21, 2,
- 57, 2, 3, 1, 37, 7, 3, 5, 195, 8, 2, 3, 1, 1, 23, 1, 84, 6, 1, 1, 4, 2, 1, 2, 238, 4, 6, 2,
- 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 3, 2, 4, 1, 5, 0, 9, 1, 2, 0,
- 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 0,
- 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1,
- 0, 2, 0, 9, 0, 5, 59, 7, 9, 4, 0, 1, 63, 17, 64, 2, 1, 2, 0, 4, 1, 7, 1, 2, 0, 2, 1, 4, 0,
- 46, 2, 23, 0, 3, 9, 16, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7,
- 1, 17, 2, 7, 1, 2, 1, 5, 0, 14, 0, 1, 61, 4, 0, 7, 109, 8, 0, 5, 0, 1, 30, 96, 128, 240, 0,
+ 80, 3, 70, 11, 49, 4, 123, 1, 54, 15, 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 2, 1, 4, 1, 10, 1,
+ 50, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3, 2, 1, 1, 2, 6, 1, 2, 1, 157, 1,
+ 3, 8, 21, 2, 57, 2, 3, 1, 37, 7, 3, 5, 195, 8, 2, 3, 1, 1, 23, 1, 84, 6, 1, 1, 4, 2, 1, 2,
+ 238, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 3, 2, 4, 1, 5,
+ 0, 9, 1, 2, 0, 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46,
+ 13, 1, 2, 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2,
+ 3, 1, 1, 1, 0, 2, 11, 2, 52, 5, 5, 1, 1, 1, 0, 17, 6, 15, 0, 5, 59, 7, 9, 4, 0, 1, 63, 17,
+ 64, 2, 1, 2, 0, 4, 1, 7, 1, 2, 0, 2, 1, 4, 0, 46, 2, 23, 0, 3, 9, 16, 2, 7, 30, 4, 148, 3,
+ 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 5, 62, 33, 1, 160,
+ 14, 0, 1, 61, 4, 0, 5, 0, 7, 109, 8, 0, 5, 0, 1, 30, 96, 128, 240, 0,
];
pub fn lookup(c: char) -> bool {
super::skip_search(
@@ -225,24 +232,24 @@ pub mod case_ignorable {
#[rustfmt::skip]
pub mod cased {
- static SHORT_OFFSET_RUNS: [u32; 21] = [
+ static SHORT_OFFSET_RUNS: [u32; 22] = [
4256, 115348384, 136322176, 144711446, 163587254, 320875520, 325101120, 350268208,
392231680, 404815649, 413205504, 421595008, 467733632, 484513952, 492924480, 497144832,
- 501339814, 578936576, 627173632, 635564336, 640872842,
+ 501339814, 578936576, 627171376, 639756544, 643952944, 649261450,
];
- static OFFSETS: [u8; 311] = [
+ static OFFSETS: [u8; 315] = [
65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 195, 1, 4, 4, 208, 1, 36, 7, 2, 30, 5,
96, 1, 42, 4, 2, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 9,
- 41, 0, 38, 1, 1, 5, 1, 2, 43, 2, 3, 0, 86, 2, 6, 0, 9, 7, 43, 2, 3, 64, 192, 64, 0, 2, 6, 2,
+ 41, 0, 38, 1, 1, 5, 1, 2, 43, 1, 4, 0, 86, 2, 6, 0, 9, 7, 43, 2, 3, 64, 192, 64, 0, 2, 6, 2,
38, 2, 6, 2, 8, 1, 1, 1, 1, 1, 1, 1, 31, 2, 53, 1, 7, 1, 1, 3, 3, 1, 7, 3, 4, 2, 6, 4, 13,
5, 3, 1, 7, 116, 1, 13, 1, 16, 13, 101, 1, 4, 1, 2, 10, 1, 1, 3, 5, 6, 1, 1, 1, 1, 1, 1, 4,
1, 6, 4, 1, 2, 4, 5, 5, 4, 1, 17, 32, 3, 2, 0, 52, 0, 229, 6, 4, 3, 2, 12, 38, 1, 1, 5, 1,
- 0, 46, 18, 30, 132, 102, 3, 4, 1, 59, 5, 2, 1, 1, 1, 5, 27, 2, 1, 3, 0, 43, 1, 13, 7, 80, 0,
+ 0, 46, 18, 30, 132, 102, 3, 4, 1, 59, 5, 2, 1, 1, 1, 5, 24, 5, 1, 3, 0, 43, 1, 14, 6, 80, 0,
7, 12, 5, 0, 26, 6, 26, 0, 80, 96, 36, 4, 36, 116, 11, 1, 15, 1, 7, 1, 2, 1, 11, 1, 15, 1,
7, 1, 2, 0, 1, 2, 3, 1, 42, 1, 9, 0, 51, 13, 51, 0, 64, 0, 64, 0, 85, 1, 71, 1, 2, 2, 1, 2,
2, 2, 4, 1, 12, 1, 1, 1, 7, 1, 65, 1, 4, 2, 8, 1, 7, 1, 28, 1, 4, 1, 5, 1, 1, 3, 7, 1, 0, 2,
- 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 10, 1, 20, 0,
- 68, 0, 26, 6, 26, 6, 26, 0,
+ 25, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 31, 1, 25, 1, 8, 0, 10, 1, 20, 6, 6,
+ 0, 62, 0, 68, 0, 26, 6, 26, 6, 26, 0,
];
pub fn lookup(c: char) -> bool {
super::skip_search(
@@ -272,14 +279,14 @@ pub mod cc {
#[rustfmt::skip]
pub mod grapheme_extend {
- static SHORT_OFFSET_RUNS: [u32; 32] = [
+ static SHORT_OFFSET_RUNS: [u32; 33] = [
768, 2098307, 6292881, 10490717, 522196754, 526393356, 731917551, 740306986, 752920175,
761309186, 778107678, 908131840, 912326558, 920715773, 924912129, 937495844, 962662059,
- 966858799, 1205935152, 1277239027, 1340173040, 1344368463, 1352776861, 1365364480,
- 1369559397, 1377950208, 1407311872, 1432478000, 1453449902, 1457645776, 1466826784,
- 1476329968,
+ 966858799, 1214323760, 1285627635, 1348547648, 1369533168, 1377922895, 1386331293,
+ 1398918912, 1403113829, 1411504640, 1440866304, 1466032814, 1495393516, 1503783120,
+ 1508769824, 1518273008,
];
- static OFFSETS: [u8; 707] = [
+ static OFFSETS: [u8; 727] = [
0, 112, 0, 7, 0, 45, 1, 1, 1, 2, 1, 2, 1, 1, 72, 11, 48, 21, 16, 1, 101, 7, 2, 6, 2, 2, 1,
4, 35, 1, 30, 27, 91, 11, 58, 9, 9, 1, 24, 4, 1, 9, 1, 3, 1, 5, 43, 3, 60, 8, 42, 24, 1, 32,
55, 1, 1, 1, 4, 8, 4, 1, 3, 7, 10, 2, 29, 1, 58, 1, 1, 1, 2, 4, 8, 1, 9, 1, 10, 2, 26, 1, 2,
@@ -287,7 +294,7 @@ pub mod grapheme_extend {
1, 1, 58, 1, 1, 2, 1, 4, 8, 1, 7, 3, 10, 2, 30, 1, 59, 1, 1, 1, 12, 1, 9, 1, 40, 1, 3, 1,
55, 1, 1, 3, 5, 3, 1, 4, 7, 2, 11, 2, 29, 1, 58, 1, 2, 1, 2, 1, 3, 1, 5, 2, 7, 2, 11, 2, 28,
2, 57, 2, 1, 1, 2, 4, 8, 1, 9, 1, 10, 2, 29, 1, 72, 1, 4, 1, 2, 3, 1, 1, 8, 1, 81, 1, 2, 7,
- 12, 8, 98, 1, 2, 9, 11, 6, 74, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1,
+ 12, 8, 98, 1, 2, 9, 11, 7, 73, 2, 27, 1, 1, 1, 1, 1, 55, 14, 1, 5, 1, 2, 5, 11, 1, 36, 9, 1,
102, 4, 1, 6, 1, 2, 2, 2, 25, 2, 4, 3, 16, 4, 13, 1, 2, 2, 6, 1, 15, 1, 0, 3, 0, 3, 29, 2,
30, 2, 30, 2, 64, 2, 1, 7, 8, 1, 2, 11, 9, 1, 45, 3, 1, 1, 117, 2, 34, 1, 118, 3, 4, 2, 9,
1, 6, 3, 219, 2, 2, 1, 58, 1, 1, 7, 1, 1, 1, 1, 2, 8, 6, 10, 2, 1, 48, 31, 49, 4, 48, 7, 1,
@@ -296,16 +303,17 @@ pub mod grapheme_extend {
4, 1, 10, 32, 2, 80, 2, 0, 1, 3, 1, 4, 1, 25, 2, 5, 1, 151, 2, 26, 18, 13, 1, 38, 8, 25, 11,
46, 3, 48, 1, 2, 4, 2, 2, 39, 1, 67, 6, 2, 2, 2, 2, 12, 1, 8, 1, 47, 1, 51, 1, 1, 3, 2, 2,
5, 2, 1, 1, 42, 2, 8, 1, 238, 1, 2, 1, 4, 1, 0, 1, 0, 16, 16, 16, 0, 2, 0, 1, 226, 1, 149,
- 5, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 0, 2, 153, 11, 49, 4, 123, 1, 54, 15, 41, 1,
- 2, 2, 10, 3, 49, 4, 2, 2, 7, 1, 61, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1, 95, 3,
- 2, 1, 1, 2, 6, 1, 160, 1, 3, 8, 21, 2, 57, 2, 1, 1, 1, 1, 22, 1, 14, 7, 3, 5, 195, 8, 2, 3,
- 1, 1, 23, 1, 81, 1, 2, 6, 1, 1, 2, 1, 1, 2, 1, 2, 235, 1, 2, 4, 6, 2, 1, 2, 27, 2, 85, 8, 2,
- 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 3, 2, 4, 1, 5, 0, 9, 1, 2, 245, 1, 10, 2, 1, 1, 4,
- 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2, 0, 7, 1, 6, 1,
- 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1, 1, 0, 2, 0, 5,
- 59, 7, 0, 1, 63, 4, 81, 1, 0, 2, 0, 46, 2, 23, 0, 1, 1, 3, 4, 5, 8, 8, 2, 7, 30, 4, 148, 3,
- 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1, 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 0, 7, 0, 1, 61, 4,
- 0, 7, 109, 7, 0, 96, 128, 240, 0,
+ 5, 0, 3, 1, 2, 5, 4, 40, 3, 4, 1, 165, 2, 0, 4, 0, 2, 80, 3, 70, 11, 49, 4, 123, 1, 54, 15,
+ 41, 1, 2, 2, 10, 3, 49, 4, 2, 2, 7, 1, 61, 3, 36, 5, 1, 8, 62, 1, 12, 2, 52, 9, 10, 4, 2, 1,
+ 95, 3, 2, 1, 1, 2, 6, 1, 2, 1, 157, 1, 3, 8, 21, 2, 57, 2, 1, 1, 1, 1, 22, 1, 14, 7, 3, 5,
+ 195, 8, 2, 3, 1, 1, 23, 1, 81, 1, 2, 6, 1, 1, 2, 1, 1, 2, 1, 2, 235, 1, 2, 4, 6, 2, 1, 2,
+ 27, 2, 85, 8, 2, 1, 1, 2, 106, 1, 1, 1, 2, 6, 1, 1, 101, 3, 2, 4, 1, 5, 0, 9, 1, 2, 245, 1,
+ 10, 2, 1, 1, 4, 1, 144, 4, 2, 2, 4, 1, 32, 10, 40, 6, 2, 4, 8, 1, 9, 6, 2, 3, 46, 13, 1, 2,
+ 0, 7, 1, 6, 1, 1, 82, 22, 2, 7, 1, 2, 1, 2, 122, 6, 3, 1, 1, 2, 1, 7, 1, 1, 72, 2, 3, 1, 1,
+ 1, 0, 2, 11, 2, 52, 5, 5, 1, 1, 1, 0, 1, 6, 15, 0, 5, 59, 7, 0, 1, 63, 4, 81, 1, 0, 2, 0,
+ 46, 2, 23, 0, 1, 1, 3, 4, 5, 8, 8, 2, 7, 30, 4, 148, 3, 0, 55, 4, 50, 8, 1, 14, 1, 22, 5, 1,
+ 15, 0, 7, 1, 17, 2, 7, 1, 2, 1, 5, 100, 1, 160, 7, 0, 1, 61, 4, 0, 4, 0, 7, 109, 7, 0, 96,
+ 128, 240, 0,
];
pub fn lookup(c: char) -> bool {
super::skip_search(
@@ -318,54 +326,56 @@ pub mod grapheme_extend {
#[rustfmt::skip]
pub mod lowercase {
- static BITSET_CHUNKS_MAP: [u8; 123] = [
+ const BITSET_CHUNKS_MAP: &'static [u8; 123] = &[
14, 17, 0, 0, 9, 0, 0, 12, 13, 10, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 4, 1, 0, 15, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0,
- 3, 0, 0, 7,
+ 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0,
+ 3, 18, 0, 7,
];
- static BITSET_INDEX_CHUNKS: [[u8; 16]; 19] = [
+ const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 20] = &[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 55, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 42, 0, 50, 46, 48, 32],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 43, 0, 51, 47, 49, 33],
[0, 0, 0, 0, 10, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26],
+ [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27],
[0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 57, 0, 55, 55, 55, 0, 21, 21, 67, 21, 35, 24, 23, 36],
- [0, 5, 74, 0, 28, 15, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 64, 33, 17, 22, 51, 52, 47, 45, 8, 34, 40, 0, 27, 13, 30],
- [11, 58, 0, 4, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 31, 0],
- [16, 25, 21, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [16, 49, 2, 20, 66, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [63, 39, 54, 12, 73, 61, 18, 1, 6, 62, 71, 19, 68, 69, 3, 44],
+ [0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 0, 57, 0, 55, 55, 55, 0, 22, 22, 67, 22, 36, 25, 24, 37],
+ [0, 5, 68, 0, 29, 15, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 64, 34, 17, 23, 52, 53, 48, 46, 8, 35, 42, 0, 28, 13, 31],
+ [11, 58, 0, 6, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 32, 0],
+ [16, 26, 22, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [16, 50, 2, 21, 66, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [16, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [63, 41, 54, 12, 75, 61, 18, 1, 7, 62, 74, 20, 71, 72, 4, 45],
];
- static BITSET_CANONICAL: [u64; 55] = [
+ const BITSET_CANONICAL: &'static [u64; 55] = &[
0b0000000000000000000000000000000000000000000000000000000000000000,
0b1111111111111111110000000000000000000000000011111111111111111111,
0b1010101010101010101010101010101010101010101010101010100000000010,
+ 0b0000000000000111111111111111111111111111111111111111111111111111,
0b1111111111111111111111000000000000000000000000001111110111111111,
- 0b0000111111111111111111111111111111111111000000000000000000000000,
0b1000000000000010000000000000000000000000000000000000000000000000,
+ 0b0000111111111111111111111111111111111111000000000000000000000000,
0b0000111111111111111111111111110000000000000000000000000011111111,
- 0b0000000000000111111111111111111111111111111111111111111111111111,
0b1111111111111111111111111111111111111111111111111010101010000101,
0b1111111111111111111111111111111100000000000000000000000000000000,
0b1111111111111111111111111111110000000000000000000000000000000000,
0b1111111111111111111111110000000000000000000000000000000000000000,
0b1111111111111111111111000000000000000000000000001111111111101111,
0b1111111111111111111100000000000000000000000000010000000000000000,
- 0b1111111111111111000000011111111111110111111111111111111111111111,
+ 0b1111111111111111000000111111111111110111111111111111111111111111,
0b1111111111111111000000000000000000000000000000000100001111000000,
0b1111111111111111000000000000000000000000000000000000000000000000,
0b1111111101111111111111111111111110000000000000000000000000000000,
0b1111110000000000000000000000000011111111111111111111111111000000,
+ 0b1111011111111111111111111111111111111111111111110000000000000000,
0b1111000000000000000000000000001111110111111111111111111111111100,
0b1010101010101010101010101010101010101010101010101101010101010100,
0b1010101010101010101010101010101010101010101010101010101010101010,
@@ -379,16 +389,16 @@ pub mod lowercase {
0b0001101111111011111111111111101111111111100000000000000000000000,
0b0001100100101111101010101010101010101010111000110111111111111111,
0b0000011111111101111111111111111111111111111111111111111110111001,
- 0b0000011101000000000000000000000000000010101010100000010100001010,
+ 0b0000011101011100000000000000000000000010101010100000010100001010,
0b0000010000100000000001000000000000000000000000000000000000000000,
0b0000000111111111111111111111111111111111111011111111111111111111,
0b0000000011111111000000001111111100000000001111110000000011111111,
0b0000000011011100000000001111111100000000110011110000000011011100,
0b0000000000001000010100000001101010101010101010101010101010101010,
0b0000000000000000001000001011111111111111111111111111111111111111,
+ 0b0000000000000000000001111110000001111111111111111111101111111111,
0b0000000000000000000000001111111111111111110111111100000000000000,
0b0000000000000000000000000001111100000000000000000000000000000011,
- 0b0000000000000000000000000000000001111111111111111111101111111111,
0b0000000000000000000000000000000000111010101010101010101010101010,
0b0000000000000000000000000000000000000000111110000000000001111111,
0b0000000000000000000000000000000000000000000000000000101111110111,
@@ -400,16 +410,16 @@ pub mod lowercase {
0b1010101010101011101010101010100000000000000000000000000000000000,
0b1101010010101010101010101010101010101010101010101010101101010101,
0b1110011001010001001011010010101001001110001001000011000100101001,
- 0b1110011111111111111111111111111111111111111111110000000000000000,
0b1110101111000000000000000000000000001111111111111111111111111100,
];
- static BITSET_MAPPING: [(u8, u8); 20] = [
+ const BITSET_MAPPING: &'static [(u8, u8); 21] = &[
(0, 64), (1, 188), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66), (1, 70),
- (1, 77), (2, 146), (2, 144), (2, 83), (3, 12), (3, 6), (4, 156), (4, 78), (5, 187),
- (6, 132), (7, 93),
+ (1, 77), (2, 146), (2, 144), (2, 83), (3, 93), (3, 147), (3, 133), (4, 12), (4, 6),
+ (5, 187), (6, 78), (7, 132),
];
- pub fn lookup(c: char) -> bool {
+ #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
+ pub const fn lookup(c: char) -> bool {
super::bitset_search(
c as u32,
&BITSET_CHUNKS_MAP,
@@ -422,14 +432,14 @@ pub mod lowercase {
#[rustfmt::skip]
pub mod n {
- static SHORT_OFFSET_RUNS: [u32; 38] = [
+ static SHORT_OFFSET_RUNS: [u32; 39] = [
1632, 18876774, 31461440, 102765417, 111154926, 115349830, 132128880, 165684320, 186656630,
195046653, 199241735, 203436434, 216049184, 241215536, 249605104, 274792208, 278987015,
283181793, 295766104, 320933114, 383848032, 392238160, 434181712, 442570976, 455154768,
- 463544256, 476128256, 480340576, 484535936, 501338848, 505534414, 513925440, 518120176,
- 522315975, 526511217, 534900992, 555875312, 561183738,
+ 463544144, 476128256, 484534880, 488730240, 505533120, 509728718, 522314048, 526508784,
+ 530703600, 534898887, 539094129, 547483904, 568458224, 573766650,
];
- static OFFSETS: [u8; 269] = [
+ static OFFSETS: [u8; 275] = [
48, 10, 120, 2, 5, 1, 2, 3, 0, 10, 134, 10, 198, 10, 0, 10, 118, 10, 4, 6, 108, 10, 118,
10, 118, 10, 2, 6, 110, 13, 115, 10, 8, 7, 103, 10, 104, 7, 7, 19, 109, 10, 96, 10, 118, 10,
70, 20, 0, 10, 70, 10, 0, 20, 0, 3, 239, 10, 6, 10, 22, 10, 0, 10, 128, 11, 165, 10, 6, 10,
@@ -439,9 +449,9 @@ pub mod n {
29, 1, 8, 1, 134, 5, 202, 10, 0, 8, 25, 7, 39, 9, 75, 5, 22, 6, 160, 2, 2, 16, 2, 46, 64, 9,
52, 2, 30, 3, 75, 5, 104, 8, 24, 8, 41, 7, 0, 6, 48, 10, 0, 31, 158, 10, 42, 4, 112, 7, 134,
30, 128, 10, 60, 10, 144, 10, 7, 20, 251, 10, 0, 10, 118, 10, 0, 10, 102, 10, 102, 12, 0,
- 19, 93, 10, 0, 29, 227, 10, 70, 10, 0, 21, 0, 111, 0, 10, 86, 10, 134, 10, 1, 7, 0, 23, 0,
- 20, 108, 25, 0, 50, 0, 10, 0, 10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4, 76, 45, 1, 15, 0, 13, 0,
- 10, 0,
+ 19, 93, 10, 0, 29, 227, 10, 70, 10, 0, 10, 102, 21, 0, 111, 0, 10, 86, 10, 134, 10, 1, 7, 0,
+ 23, 0, 20, 12, 20, 108, 25, 0, 50, 0, 10, 0, 10, 0, 10, 0, 9, 128, 10, 0, 59, 1, 3, 1, 4,
+ 76, 45, 1, 15, 0, 13, 0, 10, 0,
];
pub fn lookup(c: char) -> bool {
super::skip_search(
@@ -454,14 +464,14 @@ pub mod n {
#[rustfmt::skip]
pub mod uppercase {
- static BITSET_CHUNKS_MAP: [u8; 125] = [
+ const BITSET_CHUNKS_MAP: &'static [u8; 125] = &[
12, 15, 6, 6, 0, 6, 6, 2, 4, 11, 6, 16, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 5, 6, 14, 6, 10, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 6, 6,
6, 6, 9, 6, 3,
];
- static BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [
+ const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 17] = &[
[43, 43, 5, 34, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 5, 1],
[43, 43, 5, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43],
[43, 43, 39, 43, 43, 43, 43, 43, 17, 17, 62, 17, 42, 29, 24, 23],
@@ -480,7 +490,7 @@ pub mod uppercase {
[57, 19, 2, 18, 10, 47, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43],
[57, 37, 17, 27, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43],
];
- static BITSET_CANONICAL: [u64; 43] = [
+ const BITSET_CANONICAL: &'static [u64; 43] = &[
0b0000011111111111111111111111111000000000000000000000000000000000,
0b0000000000111111111111111111111111111111111111111111111111111111,
0b0101010101010101010101010101010101010101010101010101010000000001,
@@ -525,13 +535,14 @@ pub mod uppercase {
0b1111011111111111000000000000000000000000000000000000000000000000,
0b1111111100000000111111110000000000111111000000001111111100000000,
];
- static BITSET_MAPPING: [(u8, u8); 25] = [
+ const BITSET_MAPPING: &'static [(u8, u8); 25] = &[
(0, 187), (0, 177), (0, 171), (0, 167), (0, 164), (0, 32), (0, 47), (0, 51), (0, 121),
(0, 117), (0, 109), (1, 150), (1, 148), (1, 142), (1, 134), (1, 131), (1, 64), (2, 164),
(2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171),
];
- pub fn lookup(c: char) -> bool {
+ #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]
+ pub const fn lookup(c: char) -> bool {
super::bitset_search(
c as u32,
&BITSET_CHUNKS_MAP,
@@ -544,18 +555,26 @@ pub mod uppercase {
#[rustfmt::skip]
pub mod white_space {
- static SHORT_OFFSET_RUNS: [u32; 4] = [
- 5760, 18882560, 23080960, 40972289,
- ];
- static OFFSETS: [u8; 21] = [
- 9, 5, 18, 1, 100, 1, 26, 1, 0, 1, 0, 11, 29, 2, 5, 1, 47, 1, 0, 1, 0,
+ static WHITESPACE_MAP: [u8; 256] = [
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
+ #[inline]
pub fn lookup(c: char) -> bool {
- super::skip_search(
- c as u32,
- &SHORT_OFFSET_RUNS,
- &OFFSETS,
- )
+ match c as u32 >> 8 {
+ 0 => WHITESPACE_MAP[c as usize & 0xff] & 1 != 0,
+ 22 => c as u32 == 0x1680,
+ 32 => WHITESPACE_MAP[c as usize & 0xff] & 2 != 0,
+ 48 => c as u32 == 0x3000,
+ _ => false,
+ }
}
}
diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs
index 8a5a06b34..3ceaeadce 100644
--- a/library/core/tests/alloc.rs
+++ b/library/core/tests/alloc.rs
@@ -1,4 +1,5 @@
use core::alloc::Layout;
+use core::mem::size_of;
use core::ptr::{self, NonNull};
#[test]
@@ -13,6 +14,49 @@ fn const_unchecked_layout() {
}
#[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::<i64>();
+ 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<T>() {
+ const MAX_SIZE: usize = isize::MAX as usize;
+
+ let edge = (MAX_SIZE + 1) / size_of::<T>();
+ let low = edge.saturating_sub(10);
+ let high = edge.saturating_add(10);
+ assert!(Layout::array::<T>(low).is_ok());
+ assert!(Layout::array::<T>(high).is_err());
+ for n in low..=high {
+ assert_eq!(Layout::array::<T>(n).is_ok(), n * size_of::<T>() <= 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();
diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs
index 8ed0c8880..9538b8139 100644
--- a/library/core/tests/any.rs
+++ b/library/core/tests/any.rs
@@ -142,7 +142,7 @@ impl Provider for SomeConcreteType {
demand
.provide_ref::<String>(&self.some_string)
.provide_ref::<str>(&self.some_string)
- .provide_value::<String>(|| "bye".to_owned());
+ .provide_value_with::<String>(|| "bye".to_owned());
}
}
diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs
index 6d2cf3e83..f5f2dd047 100644
--- a/library/core/tests/ascii.rs
+++ b/library/core/tests/ascii.rs
@@ -252,6 +252,23 @@ fn test_is_ascii_digit() {
}
#[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!(
@@ -454,6 +471,7 @@ fn ascii_ctype_const() {
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];
diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
index 13b12db20..94b031060 100644
--- a/library/core/tests/atomic.rs
+++ b/library/core/tests/atomic.rs
@@ -155,7 +155,7 @@ fn ptr_add_data() {
assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1));
assert_eq!(atom.load(SeqCst), n);
- let bytes_from_n = |b| n.cast::<u8>().wrapping_add(b).cast::<i64>();
+ 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));
diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs
index 152fed803..d874f0831 100644
--- a/library/core/tests/const_ptr.rs
+++ b/library/core/tests/const_ptr.rs
@@ -3,7 +3,7 @@ const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x
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() as *const u8).add(1) as *const u16 }
+ unsafe { DATA.as_ptr().byte_add(1) }
}
#[test]
@@ -67,7 +67,7 @@ fn write() {
const fn write_unaligned() -> [u16; 2] {
let mut two_aligned = [0u16; 2];
unsafe {
- let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
+ let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1);
ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45]));
}
two_aligned
@@ -91,7 +91,7 @@ fn mut_ptr_write() {
const fn write_unaligned() -> [u16; 2] {
let mut two_aligned = [0u16; 2];
unsafe {
- let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
+ let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1);
unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45]));
}
two_aligned
diff --git a/library/core/tests/iter/adapters/array_chunks.rs b/library/core/tests/iter/adapters/array_chunks.rs
new file mode 100644
index 000000000..4e9d89e1e
--- /dev/null
+++ b/library/core/tests/iter/adapters/array_chunks.rs
@@ -0,0 +1,179 @@
+use core::cell::Cell;
+use core::iter::{self, Iterator};
+
+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::<i32>().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);
+ assert_eq!(count.get(), 10);
+}
+
+#[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
new file mode 100644
index 000000000..a9c066f0e
--- /dev/null
+++ b/library/core/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/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs
index f8ab8c9d4..690fd0c21 100644
--- a/library/core/tests/iter/adapters/flatten.rs
+++ b/library/core/tests/iter/adapters/flatten.rs
@@ -168,3 +168,45 @@ fn test_trusted_len_flatten() {
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);
+ it.advance_by(5).unwrap();
+ assert_eq!(it.clone().count(), 35);
+ it.advance_back_by(5).unwrap();
+ assert_eq!(it.clone().count(), 30);
+ it.advance_by(10).unwrap();
+ assert_eq!(it.clone().count(), 20);
+ it.advance_back_by(8).unwrap();
+ assert_eq!(it.clone().count(), 12);
+ it.advance_by(4).unwrap();
+ assert_eq!(it.clone().count(), 8);
+ it.advance_back_by(5).unwrap();
+ assert_eq!(it.clone().count(), 3);
+ it.advance_by(3).unwrap();
+ 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));
+ it.advance_by(5).unwrap(); // 5..40
+ assert_eq!(it.clone().last(), Some(39));
+ it.advance_back_by(5).unwrap(); // 5..35
+ assert_eq!(it.clone().last(), Some(34));
+ it.advance_by(10).unwrap(); // 15..35
+ assert_eq!(it.clone().last(), Some(34));
+ it.advance_back_by(8).unwrap(); // 15..27
+ assert_eq!(it.clone().last(), Some(26));
+ it.advance_by(4).unwrap(); // 19..27
+ assert_eq!(it.clone().last(), Some(26));
+ it.advance_back_by(5).unwrap(); // 19..22
+ assert_eq!(it.clone().last(), Some(21));
+ it.advance_by(3).unwrap(); // 22..22
+ assert_eq!(it.clone().last(), None);
+}
diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs
index 567d9fe49..ffd5f3857 100644
--- a/library/core/tests/iter/adapters/mod.rs
+++ b/library/core/tests/iter/adapters/mod.rs
@@ -1,3 +1,5 @@
+mod array_chunks;
+mod by_ref_sized;
mod chain;
mod cloned;
mod copied;
@@ -183,3 +185,25 @@ impl Clone for CountClone {
ret
}
}
+
+#[derive(Debug, Clone)]
+struct CountDrop<'a> {
+ dropped: bool,
+ count: &'a Cell<usize>,
+}
+
+impl<'a> CountDrop<'a> {
+ pub fn new(count: &'a Cell<usize>) -> 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/skip.rs b/library/core/tests/iter/adapters/skip.rs
index 65f235e86..754641834 100644
--- a/library/core/tests/iter/adapters/skip.rs
+++ b/library/core/tests/iter/adapters/skip.rs
@@ -201,3 +201,34 @@ fn test_skip_non_fused() {
// 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<Self::Item> {
+ <Self as Iterator>::nth(self, 0)
+ }
+
+ fn nth(&mut self, nth: usize) -> core::option::Option<Self::Item> {
+ 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/lib.rs b/library/core/tests/lib.rs
index db94368f6..51f858ade 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -2,11 +2,12 @@
#![feature(array_chunks)]
#![feature(array_methods)]
#![feature(array_windows)]
-#![feature(bench_black_box)]
+#![feature(bigint_helper_methods)]
#![feature(cell_update)]
#![feature(const_assume)]
#![feature(const_black_box)]
#![feature(const_bool_to_option)]
+#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
#![feature(const_heap)]
@@ -14,11 +15,13 @@
#![feature(const_maybe_uninit_assume_init_read)]
#![feature(const_nonnull_new)]
#![feature(const_num_from_num)]
+#![feature(const_pointer_byte_offsets)]
#![feature(const_ptr_as_ref)]
#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
#![feature(const_trait_impl)]
#![feature(const_likely)]
+#![feature(const_location_fields)]
#![feature(core_intrinsics)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
@@ -46,8 +49,8 @@
#![feature(slice_from_ptr_range)]
#![feature(split_as_slice)]
#![feature(maybe_uninit_uninit_array)]
-#![feature(maybe_uninit_array_assume_init)]
#![feature(maybe_uninit_write_slice)]
+#![feature(maybe_uninit_uninit_array_transpose)]
#![feature(min_specialization)]
#![feature(numfmt)]
#![feature(step_trait)]
@@ -61,6 +64,7 @@
#![feature(slice_partition_dedup)]
#![feature(int_log)]
#![feature(iter_advance_by)]
+#![feature(iter_array_chunks)]
#![feature(iter_collect_into)]
#![feature(iter_partition_in_place)]
#![feature(iter_intersperse)]
@@ -71,9 +75,10 @@
#![feature(iterator_try_reduce)]
#![feature(const_mut_refs)]
#![feature(const_pin)]
+#![feature(const_waker)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
-#![feature(result_into_ok_or_err)]
+#![feature(pointer_byte_offsets)]
#![feature(portable_simd)]
#![feature(ptr_metadata)]
#![feature(once_cell)]
@@ -90,12 +95,13 @@
#![feature(strict_provenance_atomic_ptr)]
#![feature(trusted_random_access)]
#![feature(unsize)]
-#![feature(unzip_option)]
#![feature(const_array_from_ref)]
#![feature(const_slice_from_ref)]
#![feature(waker_getters)]
#![feature(slice_flatten)]
#![feature(provide_any)]
+#![feature(utf8_chunks)]
+#![feature(is_ascii_octdigit)]
#![deny(unsafe_op_in_unsafe_fn)]
extern crate test;
@@ -126,6 +132,7 @@ mod nonzero;
mod num;
mod ops;
mod option;
+mod panic;
mod pattern;
mod pin;
mod pin_macro;
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
index 6856d1a1f..0362e1c8a 100644
--- a/library/core/tests/mem.rs
+++ b/library/core/tests/mem.rs
@@ -130,7 +130,11 @@ fn test_transmute_copy_grow_panics() {
payload
.downcast::<&'static str>()
.and_then(|s| {
- if *s == "cannot transmute_copy if U is larger than T" { Ok(s) } else { Err(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));
}
@@ -163,18 +167,18 @@ fn assume_init_good() {
#[test]
fn uninit_array_assume_init() {
- let mut array: [MaybeUninit<i16>; 5] = MaybeUninit::uninit_array();
+ let mut array = [MaybeUninit::<i16>::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 { MaybeUninit::array_assume_init(array) };
+ let array = unsafe { array.transpose().assume_init() };
assert_eq!(array, [3, 1, 4, 1, 5]);
- let [] = unsafe { MaybeUninit::<!>::array_assume_init([]) };
+ let [] = unsafe { [MaybeUninit::<!>::uninit(); 0].transpose().assume_init() };
}
#[test]
diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs
index dc3092e14..a1edb1a51 100644
--- a/library/core/tests/num/int_log.rs
+++ b/library/core/tests/num/int_log.rs
@@ -1,166 +1,196 @@
-//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a
+//! This tests the `Integer::{ilog,log2,log10}` methods. These tests are in a
//! separate file because there's both a large number of them, and not all tests
-//! can be run on Android. This is because in Android `log2` uses an imprecise
+//! can be run on Android. This is because in Android `ilog2` uses an imprecise
//! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53
#[test]
-fn checked_log() {
- assert_eq!(999u32.checked_log(10), Some(2));
- assert_eq!(1000u32.checked_log(10), Some(3));
- assert_eq!(555u32.checked_log(13), Some(2));
- assert_eq!(63u32.checked_log(4), Some(2));
- assert_eq!(64u32.checked_log(4), Some(3));
- assert_eq!(10460353203u64.checked_log(3), Some(21));
- assert_eq!(10460353202u64.checked_log(3), Some(20));
- assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80));
- assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79));
- assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8));
- assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7));
-
- assert_eq!(0u8.checked_log(4), None);
- assert_eq!(0u16.checked_log(4), None);
- assert_eq!(0i8.checked_log(4), None);
- assert_eq!(0i16.checked_log(4), None);
+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_log(4), None);
+ assert_eq!(i.checked_ilog(4), None);
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=i16::MAX {
- assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+ assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=u16::MAX {
- assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+ assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32));
}
}
#[test]
-fn checked_log2() {
- assert_eq!(5u32.checked_log2(), Some(2));
- assert_eq!(0u64.checked_log2(), None);
- assert_eq!(128i32.checked_log2(), Some(7));
- assert_eq!((-55i16).checked_log2(), None);
+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_log2(), None);
- assert_eq!(0u16.checked_log2(), None);
- assert_eq!(0i8.checked_log2(), None);
- assert_eq!(0i16.checked_log2(), 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);
for i in 1..=u8::MAX {
- assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=u16::MAX {
- // Guard against Android's imprecise f32::log2 implementation.
+ // Guard against Android's imprecise f32::ilog2 implementation.
if i != 8192 && i != 32768 {
- assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
}
}
for i in i8::MIN..=0 {
- assert_eq!(i.checked_log2(), None);
+ assert_eq!(i.checked_ilog2(), None);
}
for i in 1..=i8::MAX {
- assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in i16::MIN..=0 {
- assert_eq!(i.checked_log2(), None);
+ assert_eq!(i.checked_ilog2(), None);
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=i16::MAX {
- // Guard against Android's imprecise f32::log2 implementation.
+ // Guard against Android's imprecise f32::ilog2 implementation.
if i != 8192 {
- assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
}
}
}
-// Validate cases that fail on Android's imprecise float log2 implementation.
+// Validate cases that fail on Android's imprecise float ilog2 implementation.
#[test]
#[cfg(not(target_os = "android"))]
-fn checked_log2_not_android() {
- assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u32));
- assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u32));
- assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as u32));
+fn checked_ilog2_not_android() {
+ 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));
}
#[test]
-fn checked_log10() {
- assert_eq!(0u8.checked_log10(), None);
- assert_eq!(0u16.checked_log10(), None);
- assert_eq!(0i8.checked_log10(), None);
- assert_eq!(0i16.checked_log10(), None);
+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_log10(), None);
+ assert_eq!(i.checked_ilog10(), None);
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=i16::MAX {
- assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+ assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=u16::MAX {
- assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+ assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=100_000u32 {
- assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+ assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
}
}
-macro_rules! log10_loop {
- ($T:ty, $log10_max:expr) => {
- assert_eq!(<$T>::MAX.log10(), $log10_max);
- for i in 0..=$log10_max {
+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).log10(), i - 1);
- assert_eq!((p - 1).log10(), i - 1);
+ assert_eq!((p - 9).ilog10(), i - 1);
+ assert_eq!((p - 1).ilog10(), i - 1);
}
- assert_eq!(p.log10(), i);
- assert_eq!((p + 1).log10(), i);
+ assert_eq!(p.ilog10(), i);
+ assert_eq!((p + 1).ilog10(), i);
if p >= 10 {
- assert_eq!((p + 9).log10(), i);
+ assert_eq!((p + 9).ilog10(), i);
}
- // also check `x.log(10)`
+ // also check `x.ilog(10)`
if p >= 10 {
- assert_eq!((p - 9).log(10), i - 1);
- assert_eq!((p - 1).log(10), i - 1);
+ assert_eq!((p - 9).ilog(10), i - 1);
+ assert_eq!((p - 1).ilog(10), i - 1);
}
- assert_eq!(p.log(10), i);
- assert_eq!((p + 1).log(10), i);
+ assert_eq!(p.ilog(10), i);
+ assert_eq!((p + 1).ilog(10), i);
if p >= 10 {
- assert_eq!((p + 9).log(10), i);
+ assert_eq!((p + 9).ilog(10), i);
}
}
};
}
#[test]
-fn log10_u8() {
- log10_loop! { u8, 2 }
+fn ilog10_u8() {
+ ilog10_loop! { u8, 2 }
}
#[test]
-fn log10_u16() {
- log10_loop! { u16, 4 }
+fn ilog10_u16() {
+ ilog10_loop! { u16, 4 }
}
#[test]
-fn log10_u32() {
- log10_loop! { u32, 9 }
+fn ilog10_u32() {
+ ilog10_loop! { u32, 9 }
}
#[test]
-fn log10_u64() {
- log10_loop! { u64, 19 }
+fn ilog10_u64() {
+ ilog10_loop! { u64, 19 }
}
#[test]
-fn log10_u128() {
- log10_loop! { u128, 38 }
+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
index 8b84a78e6..18c55e43a 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -338,6 +338,32 @@ macro_rules! int_module {
assert_eq!(MIN.checked_next_multiple_of(-3), None);
assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN));
}
+
+ #[test]
+ fn test_carrying_add() {
+ assert_eq!($T::MAX.carrying_add(1, false), ($T::MIN, true));
+ assert_eq!($T::MAX.carrying_add(0, true), ($T::MIN, true));
+ assert_eq!($T::MAX.carrying_add(1, true), ($T::MIN + 1, true));
+ assert_eq!($T::MAX.carrying_add(-1, false), ($T::MAX - 1, false));
+ assert_eq!($T::MAX.carrying_add(-1, true), ($T::MAX, false)); // no intermediate overflow
+ assert_eq!($T::MIN.carrying_add(-1, false), ($T::MAX, true));
+ assert_eq!($T::MIN.carrying_add(-1, true), ($T::MIN, false)); // no intermediate overflow
+ assert_eq!((0 as $T).carrying_add($T::MAX, true), ($T::MIN, true));
+ assert_eq!((0 as $T).carrying_add($T::MIN, true), ($T::MIN + 1, false));
+ }
+
+ #[test]
+ fn test_borrowing_sub() {
+ assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true));
+ assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true));
+ assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true));
+ assert_eq!($T::MIN.borrowing_sub(-1, false), ($T::MIN + 1, false));
+ assert_eq!($T::MIN.borrowing_sub(-1, true), ($T::MIN, false)); // no intermediate overflow
+ assert_eq!($T::MAX.borrowing_sub(-1, false), ($T::MIN, true));
+ assert_eq!($T::MAX.borrowing_sub(-1, true), ($T::MAX, false)); // no intermediate overflow
+ assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true));
+ assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false));
+ }
}
};
}
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 49580cdcc..c79e909e4 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -172,7 +172,7 @@ fn test_can_not_overflow() {
// Calcutate the string length for the smallest overflowing number:
let max_len_string = format_radix(num, base as u128);
- // Ensure that that string length is deemed to potentially overflow:
+ // Ensure that string length is deemed to potentially overflow:
assert!(can_overflow::<$t>(base, &max_len_string));
}
)*)
diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
index 93ae620c2..15ae9f232 100644
--- a/library/core/tests/num/uint_macros.rs
+++ b/library/core/tests/num/uint_macros.rs
@@ -230,6 +230,28 @@ macro_rules! uint_module {
assert_eq!((1 as $T).checked_next_multiple_of(0), None);
assert_eq!(MAX.checked_next_multiple_of(2), None);
}
+
+ #[test]
+ fn test_carrying_add() {
+ assert_eq!($T::MAX.carrying_add(1, false), (0, true));
+ assert_eq!($T::MAX.carrying_add(0, true), (0, true));
+ assert_eq!($T::MAX.carrying_add(1, true), (1, true));
+
+ assert_eq!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false));
+ assert_eq!($T::MIN.carrying_add(0, true), (1, false));
+ assert_eq!($T::MIN.carrying_add($T::MAX, true), (0, true));
+ }
+
+ #[test]
+ fn test_borrowing_sub() {
+ assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true));
+ assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true));
+ assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true));
+
+ assert_eq!($T::MAX.borrowing_sub($T::MAX, false), (0, false));
+ assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false));
+ assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true));
+ }
}
};
}
diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs
index 8ded139a1..c5a719883 100644
--- a/library/core/tests/num/wrapping.rs
+++ b/library/core/tests/num/wrapping.rs
@@ -75,8 +75,6 @@ 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);
-// Don't warn about overflowing ops on 32-bit platforms
-#[cfg_attr(target_pointer_width = "32", allow(const_err))]
#[test]
fn wrapping_int_api() {
assert_eq!(i8::MAX.wrapping_add(1), i8::MIN);
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index 9f5e537dc..f36f7c268 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -57,6 +57,7 @@ fn test_get_resource() {
}
#[test]
+#[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))]
fn test_option_dance() {
let x = Some(());
let mut y = Some(5);
diff --git a/library/core/tests/panic.rs b/library/core/tests/panic.rs
new file mode 100644
index 000000000..24b6c56b3
--- /dev/null
+++ b/library/core/tests/panic.rs
@@ -0,0 +1 @@
+mod location;
diff --git a/library/core/tests/panic/location.rs b/library/core/tests/panic/location.rs
new file mode 100644
index 000000000..d20241d83
--- /dev/null
+++ b/library/core/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/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 12861794c..97a369810 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -650,7 +650,7 @@ fn thin_box() {
.unwrap_or_else(|| handle_alloc_error(layout))
.cast::<DynMetadata<T>>();
ptr.as_ptr().write(meta);
- ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value);
+ ptr.as_ptr().byte_add(offset).cast::<Value>().write(value);
Self { ptr, phantom: PhantomData }
}
}
diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs
index 103e8cc3a..50926da3c 100644
--- a/library/core/tests/result.rs
+++ b/library/core/tests/result.rs
@@ -96,15 +96,6 @@ fn test_unwrap_or() {
}
#[test]
-fn test_ok_or_err() {
- let ok: Result<isize, isize> = Ok(100);
- let err: Result<isize, isize> = Err(200);
-
- assert_eq!(ok.into_ok_or_err(), 100);
- assert_eq!(err.into_ok_or_err(), 200);
-}
-
-#[test]
fn test_unwrap_or_else() {
fn handler(msg: &'static str) -> isize {
if msg == "I got this." { 50 } else { panic!("BadBad") }
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 0656109e9..9e1fbea79 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -1197,7 +1197,6 @@ fn chunks_mut_are_send_and_sync() {
use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut};
use std::sync::MutexGuard;
- #[allow(unused)]
fn assert_send_and_sync()
where
ChunksMut<'static, Cell<i32>>: Send,
@@ -1210,6 +1209,8 @@ fn chunks_mut_are_send_and_sync() {
RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
{
}
+
+ assert_send_and_sync();
}
#[test]
@@ -1283,7 +1284,6 @@ fn test_windows_zip() {
}
#[test]
-#[allow(const_err)]
fn test_iter_ref_consistency() {
use std::fmt::Debug;
diff --git a/library/core/tests/str_lossy.rs b/library/core/tests/str_lossy.rs
index d4b47a470..9d3f0b65f 100644
--- a/library/core/tests/str_lossy.rs
+++ b/library/core/tests/str_lossy.rs
@@ -1,85 +1,85 @@
-use core::str::lossy::*;
+use core::str::Utf8Chunks;
#[test]
fn chunks() {
- let mut iter = Utf8Lossy::from_bytes(b"hello").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"" }), iter.next());
- assert_eq!(None, iter.next());
+ macro_rules! assert_chunks {
+ ( $string:expr, $(($valid:expr, $invalid:expr)),* $(,)? ) => {{
+ let mut iter = Utf8Chunks::new($string);
+ $(
+ let chunk = iter.next().expect("missing chunk");
+ assert_eq!($valid, chunk.valid());
+ assert_eq!($invalid, chunk.invalid());
+ )*
+ assert_eq!(None, iter.next());
+ }};
+ }
- let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"" }), iter.next());
- assert_eq!(None, iter.next());
-
- let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next());
- assert_eq!(None, iter.next());
-
- let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next());
- assert_eq!(None, iter.next());
-
- let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next());
- assert_eq!(None, iter.next());
-
- let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next());
- assert_eq!(None, iter.next());
-
- let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next());
- assert_eq!(None, iter.next());
-
- let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"" }), iter.next());
- 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
- let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next());
- assert_eq!(None, iter.next());
-}
-
-#[test]
-fn display() {
- assert_eq!(
- "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye",
- &Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string()
+ 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}\"",
+ "\"Hello\\xC0\\x80 There\\xE6\\x83 Goodbye\\u{10d4ea}\"",
&format!(
"{:?}",
- Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa")
- )
+ Utf8Chunks::new(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa").debug(),
+ ),
);
}
diff --git a/library/core/tests/task.rs b/library/core/tests/task.rs
index d71fef9e5..56be30e92 100644
--- a/library/core/tests/task.rs
+++ b/library/core/tests/task.rs
@@ -1,4 +1,4 @@
-use core::task::Poll;
+use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
#[test]
fn poll_const() {
@@ -12,3 +12,18 @@ fn poll_const() {
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) };
+
+ static CONTEXT: Context<'static> = Context::from_waker(&WAKER);
+
+ static WAKER_REF: &'static Waker = CONTEXT.waker();
+
+ WAKER_REF.wake_by_ref();
+}
diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs
index fe2d2f241..a05128de4 100644
--- a/library/core/tests/time.rs
+++ b/library/core/tests/time.rs
@@ -197,9 +197,31 @@ fn correct_sum() {
#[test]
fn debug_formatting_extreme_values() {
assert_eq!(
- format!("{:?}", Duration::new(18_446_744_073_709_551_615, 123_456_789)),
+ 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]
@@ -445,3 +467,11 @@ fn duration_const() {
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);
+}