summaryrefslogtreecommitdiffstats
path: root/library/core
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:06:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:06:37 +0000
commit246f239d9f40f633160f0c18f87a20922d4e77bb (patch)
tree5a88572663584b3d4d28e5a20e10abab1be40884 /library/core
parentReleasing progress-linux version 1.64.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-246f239d9f40f633160f0c18f87a20922d4e77bb.tar.xz
rustc-246f239d9f40f633160f0c18f87a20922d4e77bb.zip
Merging debian version 1.65.0+dfsg1-2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core')
-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.rs113
-rw-r--r--library/core/src/alloc/mod.rs10
-rw-r--r--library/core/src/any.rs244
-rw-r--r--library/core/src/array/equality.rs7
-rw-r--r--library/core/src/array/mod.rs13
-rw-r--r--library/core/src/bool.rs6
-rw-r--r--library/core/src/borrow.rs2
-rw-r--r--library/core/src/char/decode.rs11
-rw-r--r--library/core/src/char/methods.rs25
-rw-r--r--library/core/src/char/mod.rs10
-rw-r--r--library/core/src/cmp.rs34
-rw-r--r--library/core/src/convert/mod.rs11
-rw-r--r--library/core/src/default.rs2
-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.rs29
-rw-r--r--library/core/src/fmt/builders.rs18
-rw-r--r--library/core/src/fmt/mod.rs9
-rw-r--r--library/core/src/future/poll_fn.rs11
-rw-r--r--library/core/src/hash/mod.rs2
-rw-r--r--library/core/src/hint.rs21
-rw-r--r--library/core/src/intrinsics.rs438
-rw-r--r--library/core/src/iter/adapters/array_chunks.rs182
-rw-r--r--library/core/src/iter/adapters/by_ref_sized.rs29
-rw-r--r--library/core/src/iter/adapters/flatten.rs375
-rw-r--r--library/core/src/iter/adapters/mod.rs4
-rw-r--r--library/core/src/iter/adapters/skip.rs27
-rw-r--r--library/core/src/iter/mod.rs2
-rw-r--r--library/core/src/iter/traits/iterator.rs45
-rw-r--r--library/core/src/lib.rs8
-rw-r--r--library/core/src/macros/mod.rs53
-rw-r--r--library/core/src/marker.rs11
-rw-r--r--library/core/src/mem/maybe_uninit.rs10
-rw-r--r--library/core/src/mem/mod.rs10
-rw-r--r--library/core/src/mem/transmutability.rs86
-rw-r--r--library/core/src/mem/valid_align.rs18
-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/error.rs20
-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/int_macros.rs116
-rw-r--r--library/core/src/num/mod.rs14
-rw-r--r--library/core/src/num/nonzero.rs46
-rw-r--r--library/core/src/num/uint_macros.rs42
-rw-r--r--library/core/src/ops/drop.rs2
-rw-r--r--library/core/src/ops/function.rs25
-rw-r--r--library/core/src/ops/generator.rs2
-rw-r--r--library/core/src/ops/range.rs2
-rw-r--r--library/core/src/ops/try_trait.rs84
-rw-r--r--library/core/src/option.rs6
-rw-r--r--library/core/src/panicking.rs4
-rw-r--r--library/core/src/primitive_docs.rs72
-rw-r--r--library/core/src/ptr/const_ptr.rs107
-rw-r--r--library/core/src/ptr/metadata.rs18
-rw-r--r--library/core/src/ptr/mod.rs18
-rw-r--r--library/core/src/ptr/mut_ptr.rs98
-rw-r--r--library/core/src/result.rs39
-rw-r--r--library/core/src/slice/ascii.rs2
-rw-r--r--library/core/src/slice/index.rs20
-rw-r--r--library/core/src/slice/iter.rs8
-rw-r--r--library/core/src/slice/iter/macros.rs18
-rw-r--r--library/core/src/slice/memchr.rs37
-rw-r--r--library/core/src/slice/mod.rs53
-rw-r--r--library/core/src/slice/raw.rs4
-rw-r--r--library/core/src/slice/sort.rs36
-rw-r--r--library/core/src/str/error.rs20
-rw-r--r--library/core/src/str/lossy.rs244
-rw-r--r--library/core/src/str/mod.rs14
-rw-r--r--library/core/src/str/validations.rs4
-rw-r--r--library/core/src/sync/atomic.rs80
-rw-r--r--library/core/src/task/wake.rs50
-rw-r--r--library/core/src/time.rs24
-rw-r--r--library/core/src/tuple.rs2
-rw-r--r--library/core/src/unicode/unicode_data.rs65
-rw-r--r--library/core/tests/alloc.rs44
-rw-r--r--library/core/tests/any.rs2
-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.rs6
-rw-r--r--library/core/tests/num/int_log.rs156
-rw-r--r--library/core/tests/num/int_macros.rs26
-rw-r--r--library/core/tests/num/uint_macros.rs22
-rw-r--r--library/core/tests/ptr.rs2
-rw-r--r--library/core/tests/result.rs9
-rw-r--r--library/core/tests/slice.rs3
-rw-r--r--library/core/tests/str_lossy.rs138
96 files changed, 3562 insertions, 1393 deletions
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..f03502429 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -1,4 +1,12 @@
+// 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;
+#[cfg(not(bootstrap))]
+use crate::error::Error;
use crate::fmt;
use crate::mem::{self, ValidAlign};
use crate::ptr::NonNull;
@@ -52,8 +60,8 @@ 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]
@@ -62,6 +70,12 @@ impl Layout {
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.
@@ -96,8 +115,8 @@ impl Layout {
#[must_use]
#[inline]
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.
@@ -116,7 +135,7 @@ impl Layout {
without modifying the layout"]
#[inline]
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 +145,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 +159,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 +193,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 +292,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 +313,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 +370,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 +397,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 +411,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 +463,10 @@ pub type LayoutErr = LayoutError;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutError;
+#[cfg(not(bootstrap))]
+#[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..94efa7666 100644
--- a/library/core/src/alloc/mod.rs
+++ b/library/core/src/alloc/mod.rs
@@ -21,6 +21,8 @@ pub use self::layout::LayoutErr;
#[stable(feature = "alloc_layout_error", since = "1.50.0")]
pub use self::layout::LayoutError;
+#[cfg(not(bootstrap))]
+use crate::error::Error;
use crate::fmt;
use crate::ptr::{self, NonNull};
@@ -32,6 +34,14 @@ use crate::ptr::{self, NonNull};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct AllocError;
+#[cfg(not(bootstrap))]
+#[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 {
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/mod.rs b/library/core/src/array/mod.rs
index c9823a136..9effb3790 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,8 @@
use crate::borrow::{Borrow, BorrowMut};
use crate::cmp::Ordering;
use crate::convert::{Infallible, TryFrom};
+#[cfg(not(bootstrap))]
+use crate::error::Error;
use crate::fmt;
use crate::hash::{self, Hash};
use crate::iter::TrustedLen;
@@ -119,6 +121,15 @@ impl fmt::Display for TryFromSliceError {
}
}
+#[cfg(not(bootstrap))]
+#[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",
diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs
index f7a8aa0d9..7667a6508 100644
--- a/library/core/src/bool.rs
+++ b/library/core/src/bool.rs
@@ -6,6 +6,12 @@ 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
///
/// ```
diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs
index 58eabecf3..8378611eb 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")]
diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs
index 71297acd1..dc8ea66cc 100644
--- a/library/core/src/char/decode.rs
+++ b/library/core/src/char/decode.rs
@@ -1,5 +1,7 @@
//! UTF-8 and UTF-16 decoding iterators
+#[cfg(not(bootstrap))]
+use crate::error::Error;
use crate::fmt;
use super::from_u32_unchecked;
@@ -121,3 +123,12 @@ impl fmt::Display for DecodeUtf16Error {
write!(f, "unpaired surrogate found: {:x}", self.code)
}
}
+
+#[cfg(not(bootstrap))]
+#[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..b7a63b7c6 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -746,10 +746,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 +788,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 +910,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
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index 0df23e7bb..72d63ac4b 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,8 @@ 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;
+#[cfg(not(bootstrap))]
+use crate::error::Error;
use crate::fmt::{self, Write};
use crate::iter::FusedIterator;
@@ -582,3 +586,7 @@ impl fmt::Display for TryFromCharError {
"unicode code point out of range".fmt(fmt)
}
}
+
+#[cfg(not(bootstrap))]
+#[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..d9f2d3d64 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
@@ -23,6 +23,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::marker::Destruct;
+use crate::marker::StructuralPartialEq;
use self::Ordering::*;
@@ -38,8 +39,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
@@ -225,7 +228,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 +339,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 +886,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]
@@ -1139,11 +1155,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.
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index b30c8a4ae..05637c166 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -34,6 +34,8 @@
#![stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(bootstrap))]
+use crate::error::Error;
use crate::fmt;
use crate::hash::{Hash, Hasher};
@@ -556,6 +558,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 +718,14 @@ impl fmt::Display for Infallible {
}
}
+#[cfg(not(bootstrap))]
+#[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..b53cd6074 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")]
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..4a8efe15e
--- /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()
+ }
+}
+
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+impl Error for crate::time::FromFloatSecsError {}
+
+#[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..21f80ec02 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())
}
}
@@ -299,7 +294,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 +344,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 +384,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);
@@ -497,7 +495,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 +523,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 +547,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..905212eb3 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
///
/// ```
@@ -1815,7 +1819,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 +1827,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 +2567,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
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/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..764e27962 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>) {
@@ -160,19 +160,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
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index cabc5017f..11c75e2c9 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -54,7 +54,9 @@
)]
#![allow(missing_docs)]
-use crate::marker::{Destruct, DiscriminantKind};
+#[cfg(bootstrap)]
+use crate::marker::Destruct;
+use crate::marker::DiscriminantKind;
use crate::mem;
// These imports are used for simplifying intra-doc links
@@ -63,7 +65,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 +73,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 +739,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
@@ -1313,7 +1084,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,7 +1234,7 @@ 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;
@@ -1518,6 +1289,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(not(bootstrap))]
+ 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>()`
@@ -2223,29 +2005,32 @@ 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")]
+ #[cfg(not(bootstrap))]
+ pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
+
+ #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
+ #[cfg(bootstrap)]
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")]
+ #[cfg(bootstrap)]
pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
/// Allocates a block of memory at compile time.
@@ -2282,7 +2067,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.
///
@@ -2299,13 +2085,70 @@ extern "rust-intrinsic" {
/// `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.
+ #[cfg(not(bootstrap))]
+ #[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 +2159,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 +2178,21 @@ 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) => {
+ ($([$($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();
}
- };
- 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 +2201,7 @@ 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 the regions of memory starting at `src` and `dst` of size
@@ -2365,6 +2216,16 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
diff >= size
}
+#[cfg(bootstrap)]
+pub const fn ptr_guaranteed_cmp(a: *const (), b: *const ()) -> u8 {
+ match (ptr_guaranteed_eq(a, b), ptr_guaranteed_ne(a, b)) {
+ (false, false) => 2,
+ (true, false) => 1,
+ (false, true) => 0,
+ (true, true) => unreachable!(),
+ }
+}
+
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
/// and destination must *not* overlap.
///
@@ -2420,9 +2281,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 +2312,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
@@ -2464,7 +2325,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
// SAFETY: the safety contract for `copy_nonoverlapping` must be
// upheld by the caller.
unsafe {
- assert_unsafe_precondition!(
+ assert_unsafe_precondition!([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 +2399,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 +2411,8 @@ 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!([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 +2468,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,63 +2480,12 @@ 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!([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.
+#[cfg(bootstrap)]
#[unstable(
feature = "const_eval_select",
issue = "none",
@@ -2696,6 +2507,7 @@ where
called_at_rt.call_once(arg)
}
+#[cfg(bootstrap)]
#[unstable(
feature = "const_eval_select",
issue = "none",
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..9b479a9f8
--- /dev/null
+++ b/library/core/src/iter/adapters/array_chunks.rs
@@ -0,0 +1,182 @@
+use crate::array;
+use crate::iter::{ByRefSized, FusedIterator, Iterator};
+use crate::ops::{ControlFlow, NeverShortCircuit, 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 };
+ }
+ }
+ }
+ }
+
+ fn fold<B, F>(mut self, init: B, f: F) -> B
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> B,
+ {
+ self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0
+ }
+}
+
+#[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 }
+ }
+
+ fn rfold<B, F>(mut self, init: B, f: F) -> B
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> B,
+ {
+ self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0
+ }
+}
+
+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..477e7117c 100644
--- a/library/core/src/iter/adapters/by_ref_sized.rs
+++ b/library/core/src/iter/adapters/by_ref_sized.rs
@@ -1,4 +1,4 @@
-use crate::ops::Try;
+use crate::ops::{NeverShortCircuit, Try};
/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
///
@@ -8,28 +8,31 @@ 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]
@@ -37,7 +40,8 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
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, NeverShortCircuit::wrap_mut_2(f)).0
}
#[inline]
@@ -46,7 +50,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,17 +58,17 @@ 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]
@@ -72,7 +76,8 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
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, NeverShortCircuit::wrap_mut_2(f)).0
}
#[inline]
@@ -81,6 +86,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/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/mod.rs b/library/core/src/iter/adapters/mod.rs
index 916a26e24..bf4fabad3 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};
+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;
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index 2c283100f..dbf0ae9ec 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]
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index d5c6aed5b..9514466bd 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -398,6 +398,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/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 275412b57..b2d08f4b0 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::{
@@ -3316,6 +3316,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.
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 24742bb49..5621d15c1 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)]
@@ -130,7 +131,6 @@
#![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)]
@@ -143,12 +143,14 @@
#![feature(const_type_id)]
#![feature(const_type_name)]
#![feature(const_default_impls)]
+#![feature(const_unicode_case_lookup)]
#![feature(const_unsafecell_get_mut)]
#![feature(core_panic)]
#![feature(duration_consts_float)]
#![feature(maybe_uninit_uninit_array)]
#![feature(ptr_metadata)]
#![feature(slice_ptr_get)]
+#![feature(slice_split_at_unchecked)]
#![feature(str_internals)]
#![feature(utf16_extra)]
#![feature(utf16_extra_const)]
@@ -157,9 +159,11 @@
#![feature(const_slice_from_ref)]
#![feature(const_slice_index)]
#![feature(const_is_char_boundary)]
+#![feature(const_cstr_methods)]
//
// Language features:
#![feature(abi_unadjusted)]
+#![feature(adt_const_params)]
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
#![feature(associated_type_bounds)]
@@ -302,6 +306,8 @@ pub mod clone;
pub mod cmp;
pub mod convert;
pub mod default;
+#[cfg(not(bootstrap))]
+pub mod error;
pub mod marker;
pub mod ops;
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..b8239ed88 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -343,7 +343,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`?
///
@@ -800,6 +800,15 @@ impl<T: ?Sized> Unpin for *mut T {}
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
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")]
+#[cfg_attr(not(bootstrap), 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..2490c0767 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]);
/// }
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 20b2d5e26..d2dd2941d 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -665,14 +665,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
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
index b59a5b89d..87a378631 100644
--- a/library/core/src/mem/transmutability.rs
+++ b/library/core/src/mem/transmutability.rs
@@ -9,20 +9,15 @@
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")]
+#[cfg_attr(not(bootstrap), 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/mem/valid_align.rs b/library/core/src/mem/valid_align.rs
index fcfa95120..32b2afb72 100644
--- a/library/core/src/mem/valid_align.rs
+++ b/library/core/src/mem/valid_align.rs
@@ -1,4 +1,5 @@
use crate::convert::TryFrom;
+use crate::intrinsics::assert_unsafe_precondition;
use crate::num::NonZeroUsize;
use crate::{cmp, fmt, hash, mem, num};
@@ -26,7 +27,8 @@ impl ValidAlign {
/// It must *not* be zero.
#[inline]
pub(crate) const unsafe fn new_unchecked(align: usize) -> Self {
- debug_assert!(align.is_power_of_two());
+ // SAFETY: Precondition passed to the caller.
+ unsafe { assert_unsafe_precondition!((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.
@@ -34,9 +36,14 @@ impl ValidAlign {
}
#[inline]
+ pub(crate) const fn as_usize(self) -> usize {
+ self.0 as usize
+ }
+
+ #[inline]
pub(crate) 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.
@@ -46,6 +53,13 @@ impl ValidAlign {
pub(crate) fn log2(self) -> u32 {
self.as_nonzero().trailing_zeros()
}
+
+ /// Returns the alignment for a type.
+ #[inline]
+ pub(crate) fn of<T>() -> Self {
+ // SAFETY: rustc ensures that type alignment is always a power of two.
+ unsafe { ValidAlign::new_unchecked(mem::align_of::<T>()) }
+ }
}
impl fmt::Debug for ValidAlign {
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/error.rs b/library/core/src/num/error.rs
index 1a223016d..1f6b40e5d 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -1,6 +1,8 @@
//! Error types for conversion to integral types.
use crate::convert::Infallible;
+#[cfg(not(bootstrap))]
+use crate::error::Error;
use crate::fmt;
/// The error type returned when a checked integral type conversion fails.
@@ -144,3 +146,21 @@ impl fmt::Display for ParseIntError {
self.__description().fmt(f)
}
}
+
+#[cfg(not(bootstrap))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Error for ParseIntError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.__description()
+ }
+}
+
+#[cfg(not(bootstrap))]
+#[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/int_macros.rs b/library/core/src/num/int_macros.rs
index a66de19ba..e7deb728d 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1518,6 +1518,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
@@ -1569,6 +1614,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
@@ -2204,7 +2282,7 @@ 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
@@ -2217,7 +2295,7 @@ macro_rules! int_impl {
///
/// ```
/// #![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, \
@@ -2226,8 +2304,8 @@ macro_rules! int_impl {
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log(self, base: Self) -> u32 {
- match self.checked_log(base) {
+ pub const fn ilog(self, base: Self) -> u32 {
+ match self.checked_ilog(base) {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
@@ -2250,7 +2328,7 @@ macro_rules! int_impl {
///
/// ```
/// #![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, \
@@ -2259,8 +2337,8 @@ macro_rules! int_impl {
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log2(self) -> u32 {
- match self.checked_log2() {
+ pub const fn ilog2(self) -> u32 {
+ match self.checked_ilog2() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
@@ -2283,7 +2361,7 @@ macro_rules! int_impl {
///
/// ```
/// #![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, \
@@ -2292,8 +2370,8 @@ macro_rules! int_impl {
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log10(self) -> u32 {
- match self.checked_log10() {
+ pub const fn ilog10(self) -> u32 {
+ match self.checked_ilog10() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
@@ -2311,20 +2389,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 +2411,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 +2432,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 +2456,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..ab17aa0c8 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -3,6 +3,8 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::ascii;
+#[cfg(not(bootstrap))]
+use crate::error::Error;
use crate::intrinsics;
use crate::mem;
use crate::ops::{Add, Mul, Sub};
@@ -57,6 +59,16 @@ pub use wrapping::Wrapping;
#[cfg(not(no_fp_fmt_parse))]
pub use dec2flt::ParseFloatError;
+#[cfg(not(bootstrap))]
+#[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;
@@ -623,7 +635,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
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 4de0a0cf5..532a09736 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -56,7 +56,7 @@ 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!((n: $Int) => n != 0);
Self(n)
}
}
@@ -309,8 +309,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 +346,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 +377,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 +409,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 +450,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 +460,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 +485,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 +545,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.
///
@@ -740,8 +740,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 +777,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 +809,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 +849,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..46fd7f2d0 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -688,7 +688,7 @@ 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
@@ -700,7 +700,7 @@ macro_rules! uint_impl {
///
/// ```
/// #![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, \
@@ -709,8 +709,8 @@ macro_rules! uint_impl {
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log(self, base: Self) -> u32 {
- match self.checked_log(base) {
+ pub const fn ilog(self, base: Self) -> u32 {
+ match self.checked_ilog(base) {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
@@ -733,7 +733,7 @@ macro_rules! uint_impl {
///
/// ```
/// #![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, \
@@ -742,8 +742,8 @@ macro_rules! uint_impl {
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log2(self) -> u32 {
- match self.checked_log2() {
+ pub const fn ilog2(self) -> u32 {
+ match self.checked_ilog2() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
@@ -766,7 +766,7 @@ macro_rules! uint_impl {
///
/// ```
/// #![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, \
@@ -775,8 +775,8 @@ macro_rules! uint_impl {
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log10(self) -> u32 {
- match self.checked_log10() {
+ pub const fn ilog10(self) -> u32 {
+ match self.checked_ilog10() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
@@ -794,20 +794,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 +816,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 +837,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 +859,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
}
diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs
index aa654aa55..de9ddb852 100644
--- a/library/core/src/ops/drop.rs
+++ b/library/core/src/ops/drop.rs
@@ -156,7 +156,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..8fdf22cf6 100644
--- a/library/core/src/ops/function.rs
+++ b/library/core/src/ops/function.rs
@@ -250,9 +250,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 +261,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 +272,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 +285,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 +296,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..3ebd6f8cd 100644
--- a/library/core/src/ops/generator.rs
+++ b/library/core/src/ops/generator.rs
@@ -83,7 +83,7 @@ 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"]
+ #[cfg_attr(bootstrap, lang = "generator_return")]
type Return;
/// Resumes the execution of this generator.
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..10f041344 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -222,7 +222,87 @@ pub trait Try: FromResidual {
/// Every `Try` type needs to be recreatable from its own associated
/// `Residual` type, but can also have additional `FromResidual` implementations
/// to support interconversion with other `Try` types.
-#[rustc_on_unimplemented(
+#[cfg_attr(not(bootstrap), rustc_on_unimplemented(
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::result::Result<T, E>",
+ R = "std::option::Option<std::convert::Infallible>"
+ ),
+ 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}`",
+ parent_label = "this function returns a `Result`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::result::Result<T, E>",
+ ),
+ // There's a special error message in the trait selection code for
+ // `From` in `?`, so this is not shown for result-in-result errors,
+ // and thus it can be phrased more strongly than `ControlFlow`'s.
+ message = "the `?` operator can only be used on `Result`s \
+ in {ItemContext} that returns `Result`",
+ label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+ parent_label = "this function returns a `Result`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::option::Option<T>",
+ R = "std::result::Result<T, E>",
+ ),
+ 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",
+ parent_label = "this function returns an `Option`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::option::Option<T>",
+ ),
+ // `Option`-in-`Option` always works, as there's only one possible
+ // residual, so this can also be phrased strongly.
+ message = "the `?` operator can only be used on `Option`s \
+ in {ItemContext} that returns `Option`",
+ label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+ parent_label = "this function returns an `Option`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::ops::ControlFlow<B, C>",
+ R = "std::ops::ControlFlow<B, C>",
+ ),
+ 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}`",
+ parent_label = "this function returns a `ControlFlow`",
+ note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
+ ),
+ on(
+ all(
+ from_desugaring = "QuestionMark",
+ _Self = "std::ops::ControlFlow<B, C>",
+ // `R` is not a `ControlFlow`, as that case was matched previously
+ ),
+ message = "the `?` operator can only be used on `ControlFlow`s \
+ in {ItemContext} that returns `ControlFlow`",
+ label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+ parent_label = "this function returns a `ControlFlow`",
+ ),
+ on(
+ all(from_desugaring = "QuestionMark"),
+ message = "the `?` operator can only be used in {ItemContext} \
+ that returns `Result` or `Option` \
+ (or another type that implements `{FromResidual}`)",
+ label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
+ parent_label = "this function should return `Result` or `Option` to accept `?`"
+ ),
+))]
+#[cfg_attr(bootstrap, rustc_on_unimplemented(
on(
all(
from_desugaring = "QuestionMark",
@@ -301,7 +381,7 @@ pub trait Try: FromResidual {
label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
),
-)]
+))]
#[rustc_diagnostic_item = "FromResidual"]
#[unstable(feature = "try_trait_v2", issue = "84277")]
pub trait FromResidual<R = <Self as Try>::Residual> {
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index bca73cb77..934175863 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1189,6 +1189,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
///
/// ```
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 7a575a88e..d4afe0f53 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -190,11 +190,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..242f44ade 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -801,11 +801,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 +858,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 +1041,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 +1052,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 +1223,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 +1529,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 +1545,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/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index e0655d68d..43e883b8b 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,21 @@ 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.
+ #[cfg(not(bootstrap))]
+ #[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 +659,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
@@ -740,9 +758,12 @@ 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!([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 +773,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 +791,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 +821,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 +1286,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 +1356,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..8865c834c 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -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..e976abed7 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).
//!
@@ -603,6 +603,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 +640,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,
@@ -884,7 +886,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
// SAFETY: the caller must guarantee that `x` and `y` are
// valid for writes and properly aligned.
unsafe {
- assert_unsafe_precondition!(
+ assert_unsafe_precondition!([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 +983,7 @@ 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!([T](dst: *mut T) => is_aligned_and_not_null(dst));
mem::swap(&mut *dst, &mut src); // cannot overlap
}
src
@@ -1468,7 +1470,7 @@ 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!([T](src: *const T) => is_aligned_and_not_null(src));
intrinsics::volatile_load(src)
}
}
@@ -1539,7 +1541,7 @@ 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!([T](dst: *mut T) => is_aligned_and_not_null(dst));
intrinsics::volatile_store(dst, src);
}
}
@@ -1834,7 +1836,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
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index fc3dd2a9b..e277b8181 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.
@@ -100,8 +103,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 +163,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 +258,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 +578,21 @@ 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.
+ #[cfg(not(bootstrap))]
+ #[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 +700,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 +718,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 +745,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 +834,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
@@ -1545,20 +1555,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 +1627,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/result.rs b/library/core/src/result.rs
index 45b052c82..76eaa191f 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1285,6 +1285,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 +1776,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)]
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..3403a5a86 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");
}
@@ -217,21 +223,23 @@ 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!([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!([T](this: usize, slice: *mut [T]) => this < slice.len());
slice.as_mut_ptr().add(self)
}
}
@@ -276,22 +284,26 @@ 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!([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!([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..395c56784 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -92,7 +92,7 @@ impl<'a, T> Iter<'a, T> {
assume(!ptr.is_null());
let end = if mem::size_of::<T>() == 0 {
- (ptr as *const u8).wrapping_add(slice.len()) as *const T
+ ptr.wrapping_byte_add(slice.len())
} else {
ptr.add(slice.len())
};
@@ -228,7 +228,7 @@ impl<'a, T> IterMut<'a, T> {
assume(!ptr.is_null());
let end = if mem::size_of::<T>() == 0 {
- (ptr as *mut u8).wrapping_add(slice.len()) as *mut T
+ ptr.wrapping_byte_add(slice.len())
} else {
ptr.add(slice.len())
};
@@ -2754,10 +2754,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..6c9e7574e 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,7 +99,7 @@ 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 {
+ unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T {
if mem::size_of::<T>() == 0 {
zst_shrink!(self, offset);
self.ptr.as_ptr()
@@ -107,7 +107,7 @@ macro_rules! iterator {
// 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
}
}
@@ -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) }
}
@@ -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..7de1f48e6 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`.
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index e6ca6ef82..6a7150d29 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -656,10 +656,11 @@ 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!([T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len());
ptr::swap(ptr.add(a), ptr.add(b));
}
}
@@ -674,8 +675,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 +700,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 +710,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 +973,10 @@ 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!([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 +1113,11 @@ 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!([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 +1544,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) }
}
@@ -1623,11 +1630,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.
@@ -1675,7 +1690,7 @@ 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!((mid: usize, len: usize) => mid <= len);
(from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid))
}
}
@@ -2309,7 +2324,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
@@ -2921,7 +2936,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;
@@ -3518,7 +3533,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() {
@@ -4101,7 +4116,6 @@ impl<T, const N: usize> [[T; N]] {
}
}
-#[cfg(not(bootstrap))]
#[cfg(not(test))]
impl [f32] {
/// Sorts the slice of floats.
@@ -4131,7 +4145,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..f1e8bc79b 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -90,7 +90,7 @@ use crate::ptr;
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!(
+ assert_unsafe_precondition!([T](data: *const T, len: usize) =>
is_aligned_and_not_null(data)
&& crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize
);
@@ -134,7 +134,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
unsafe {
- assert_unsafe_precondition!(
+ assert_unsafe_precondition!([T](data: *mut T, len: usize) =>
is_aligned_and_not_null(data)
&& crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize
);
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 6a201834b..c6c03c0b0 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -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)
diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs
index 4e569fcc8..343889b69 100644
--- a/library/core/src/str/error.rs
+++ b/library/core/src/str/error.rs
@@ -1,5 +1,7 @@
//! Defines utf8 error type.
+#[cfg(not(bootstrap))]
+use crate::error::Error;
use crate::fmt;
/// Errors which can occur when attempting to interpret a sequence of [`u8`]
@@ -122,6 +124,15 @@ impl fmt::Display for Utf8Error {
}
}
+#[cfg(not(bootstrap))]
+#[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 +147,12 @@ impl fmt::Display for ParseBoolError {
"provided string was not `true` or `false`".fmt(f)
}
}
+
+#[cfg(not(bootstrap))]
+#[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..f673aa2a4 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,7 @@ impl_fn_for_zst! {
unsafe { from_utf8_unchecked(bytes) }
};
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(bootstrap))]
+impl !crate::error::Error for &str {}
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..3c96290fc 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -1554,8 +1554,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 +1565,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 +1583,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 +1601,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,16 +1618,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_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,
@@ -1687,16 +1669,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_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
@@ -1745,16 +1719,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_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
@@ -1801,16 +1767,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() }
}
}
@@ -3073,30 +3031,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 +3066,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/task/wake.rs b/library/core/src/task/wake.rs
index 87d4a25af..60ecc9c0b 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,7 +184,7 @@ 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")]
#[must_use]
#[inline]
@@ -180,7 +192,7 @@ impl<'a> Context<'a> {
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")]
#[must_use]
#[inline]
@@ -202,7 +214,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 +242,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 +276,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 +289,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
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 756f1a166..4f29ecc0f 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -318,19 +318,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")]
@@ -1143,7 +1135,7 @@ 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() {
+ 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 {
@@ -1288,7 +1280,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 +1299,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) {
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index d189e6400..aa8a2425b 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -107,7 +107,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/unicode_data.rs b/library/core/src/unicode/unicode_data.rs
index d2073f86c..7301da2af 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];
@@ -318,14 +323,14 @@ 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,
];
- static BITSET_INDEX_CHUNKS: [[u8; 16]; 19] = [
+ const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 19] = &[
[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],
@@ -346,7 +351,7 @@ pub mod lowercase {
[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],
];
- static BITSET_CANONICAL: [u64; 55] = [
+ const BITSET_CANONICAL: &'static [u64; 55] = &[
0b0000000000000000000000000000000000000000000000000000000000000000,
0b1111111111111111110000000000000000000000000011111111111111111111,
0b1010101010101010101010101010101010101010101010101010100000000010,
@@ -403,13 +408,14 @@ pub mod lowercase {
0b1110011111111111111111111111111111111111111111110000000000000000,
0b1110101111000000000000000000000000001111111111111111111111111100,
];
- static BITSET_MAPPING: [(u8, u8); 20] = [
+ const BITSET_MAPPING: &'static [(u8, u8); 20] = &[
(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),
];
- 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,
@@ -454,14 +460,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 +486,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 +531,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 +551,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/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..4a0e162bc 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -3,6 +3,7 @@
#![feature(array_methods)]
#![feature(array_windows)]
#![feature(bench_black_box)]
+#![feature(bigint_helper_methods)]
#![feature(cell_update)]
#![feature(const_assume)]
#![feature(const_black_box)]
@@ -14,6 +15,7 @@
#![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)]
@@ -61,6 +63,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)]
@@ -73,7 +76,7 @@
#![feature(const_pin)]
#![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)]
@@ -96,6 +99,7 @@
#![feature(waker_getters)]
#![feature(slice_flatten)]
#![feature(provide_any)]
+#![feature(utf8_chunks)]
#![deny(unsafe_op_in_unsafe_fn)]
extern crate test;
diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs
index dc3092e14..be203fb5c 100644
--- a/library/core/tests/num/int_log.rs
+++ b/library/core/tests/num/int_log.rs
@@ -1,166 +1,166 @@
-//! 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 }
}
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/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/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..b8f6fe696 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]
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(),
+ ),
);
}