summaryrefslogtreecommitdiffstats
path: root/library/core
diff options
context:
space:
mode:
Diffstat (limited to 'library/core')
-rw-r--r--library/core/benches/iter.rs1
-rw-r--r--library/core/src/any.rs590
-rw-r--r--library/core/src/array/mod.rs2
-rw-r--r--library/core/src/ascii/ascii_char.rs4
-rw-r--r--library/core/src/borrow.rs2
-rw-r--r--library/core/src/cell.rs3
-rw-r--r--library/core/src/cell/once.rs8
-rw-r--r--library/core/src/clone.rs40
-rw-r--r--library/core/src/cmp.rs16
-rw-r--r--library/core/src/default.rs45
-rw-r--r--library/core/src/error.md6
-rw-r--r--library/core/src/error.rs745
-rw-r--r--library/core/src/escape.rs4
-rw-r--r--library/core/src/ffi/c_str.rs35
-rw-r--r--library/core/src/ffi/mod.rs8
-rw-r--r--library/core/src/fmt/builders.rs6
-rw-r--r--library/core/src/fmt/mod.rs20
-rw-r--r--library/core/src/intrinsics.rs56
-rw-r--r--library/core/src/intrinsics/mir.rs12
-rw-r--r--library/core/src/iter/adapters/flatten.rs7
-rw-r--r--library/core/src/iter/adapters/map_windows.rs293
-rw-r--r--library/core/src/iter/adapters/mod.rs4
-rw-r--r--library/core/src/iter/mod.rs8
-rw-r--r--library/core/src/iter/traits/collect.rs6
-rw-r--r--library/core/src/iter/traits/double_ended.rs62
-rw-r--r--library/core/src/iter/traits/iterator.rs222
-rw-r--r--library/core/src/lib.rs11
-rw-r--r--library/core/src/macros/mod.rs1
-rw-r--r--library/core/src/marker.rs19
-rw-r--r--library/core/src/mem/transmutability.rs4
-rw-r--r--library/core/src/net/ip_addr.rs170
-rw-r--r--library/core/src/num/int_macros.rs1
-rw-r--r--library/core/src/num/uint_macros.rs13
-rw-r--r--library/core/src/option.rs36
-rw-r--r--library/core/src/panic/panic_info.rs10
-rw-r--r--library/core/src/panicking.rs14
-rw-r--r--library/core/src/ptr/const_ptr.rs17
-rw-r--r--library/core/src/ptr/metadata.rs3
-rw-r--r--library/core/src/ptr/mod.rs1
-rw-r--r--library/core/src/ptr/mut_ptr.rs17
-rw-r--r--library/core/src/ptr/non_null.rs29
-rw-r--r--library/core/src/ptr/unique.rs2
-rw-r--r--library/core/src/result.rs3
-rw-r--r--library/core/src/slice/cmp.rs21
-rw-r--r--library/core/src/slice/index.rs6
-rw-r--r--library/core/src/slice/iter.rs25
-rw-r--r--library/core/src/slice/iter/macros.rs146
-rw-r--r--library/core/src/slice/mod.rs4
-rw-r--r--library/core/src/str/iter.rs21
-rw-r--r--library/core/src/str/mod.rs20
-rw-r--r--library/core/src/str/pattern.rs4
-rw-r--r--library/core/src/str/traits.rs52
-rw-r--r--library/core/src/sync/atomic.rs147
-rw-r--r--library/core/src/tuple.rs2
-rw-r--r--library/core/tests/any.rs62
-rw-r--r--library/core/tests/error.rs66
-rw-r--r--library/core/tests/iter/adapters/map_windows.rs283
-rw-r--r--library/core/tests/iter/adapters/mod.rs1
-rw-r--r--library/core/tests/iter/traits/iterator.rs31
-rw-r--r--library/core/tests/lib.rs7
-rw-r--r--library/core/tests/manually_drop.rs2
-rw-r--r--library/core/tests/slice.rs28
62 files changed, 2345 insertions, 1139 deletions
diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs
index 5ec22e514..05fec0c4b 100644
--- a/library/core/benches/iter.rs
+++ b/library/core/benches/iter.rs
@@ -473,6 +473,7 @@ fn bench_next_chunk_copied(b: &mut Bencher) {
/// Exercises the TrustedRandomAccess specialization in ArrayChunks
#[bench]
+#[allow(noop_method_call)]
fn bench_next_chunk_trusted_random_access(b: &mut Bencher) {
let v = vec![1u8; 1024];
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index 09f52d692..8f5404d97 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -83,72 +83,6 @@
//! }
//! ```
//!
-//! # `Provider` and `Demand`
-//!
-//! `Provider` and the associated APIs support generic, type-driven access to data, and a mechanism
-//! for implementers to provide such data. The key parts of the interface are the `Provider`
-//! trait for objects which can provide data, and the [`request_value`] and [`request_ref`]
-//! functions for requesting data from an object which implements `Provider`. Generally, end users
-//! should not call `request_*` directly, they are helper functions for intermediate implementers
-//! to use to implement a user-facing interface. This is purely for the sake of ergonomics, there is
-//! no safety concern here; intermediate implementers can typically support methods rather than
-//! free functions and use more specific names.
-//!
-//! Typically, a data provider is a trait object of a trait which extends `Provider`. A user will
-//! request data from a trait object by specifying the type of the data.
-//!
-//! ## Data flow
-//!
-//! * A user requests an object of a specific type, which is delegated to `request_value` or
-//! `request_ref`
-//! * `request_*` creates a `Demand` object and passes it to `Provider::provide`
-//! * The data provider's implementation of `Provider::provide` tries providing values of
-//! different types using `Demand::provide_*`. If the type matches the type requested by
-//! the user, the value will be stored in the `Demand` object.
-//! * `request_*` unpacks the `Demand` object and returns any stored value to the user.
-//!
-//! ## Examples
-//!
-//! ```
-//! # #![feature(provide_any)]
-//! use std::any::{Provider, Demand, request_ref};
-//!
-//! // Definition of MyTrait, a data provider.
-//! trait MyTrait: Provider {
-//! // ...
-//! }
-//!
-//! // Methods on `MyTrait` trait objects.
-//! impl dyn MyTrait + '_ {
-//! /// Get a reference to a field of the implementing struct.
-//! pub fn get_context_by_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
-//! request_ref::<T>(self)
-//! }
-//! }
-//!
-//! // Downstream implementation of `MyTrait` and `Provider`.
-//! # struct SomeConcreteType { some_string: String }
-//! impl MyTrait for SomeConcreteType {
-//! // ...
-//! }
-//!
-//! impl Provider for SomeConcreteType {
-//! fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
-//! // Provide a string reference. We could provide multiple values with
-//! // different types here.
-//! demand.provide_ref::<String>(&self.some_string);
-//! }
-//! }
-//!
-//! // Downstream usage of `MyTrait`.
-//! fn use_my_trait(obj: &dyn MyTrait) {
-//! // Request a &String from obj.
-//! let _ = obj.get_context_by_ref::<String>().unwrap();
-//! }
-//! ```
-//!
-//! In this example, if the concrete type of `obj` in `use_my_trait` is `SomeConcreteType`, then
-//! the `get_context_by_ref` call will return a reference to `obj.some_string` with type `&String`.
#![stable(feature = "rust1", since = "1.0.0")]
@@ -697,9 +631,6 @@ impl TypeId {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
pub const fn of<T: ?Sized + 'static>() -> TypeId {
- #[cfg(bootstrap)]
- let t = intrinsics::type_id::<T>() as u128;
- #[cfg(not(bootstrap))]
let t: u128 = intrinsics::type_id::<T>();
TypeId { t }
}
@@ -801,524 +732,3 @@ pub const fn type_name<T: ?Sized>() -> &'static str {
pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
type_name::<T>()
}
-
-///////////////////////////////////////////////////////////////////////////////
-// Provider trait
-///////////////////////////////////////////////////////////////////////////////
-
-/// Trait implemented by a type which can dynamically provide values based on type.
-#[unstable(feature = "provide_any", issue = "96024")]
-pub trait Provider {
- /// Data providers should implement this method to provide *all* values they are able to
- /// provide by using `demand`.
- ///
- /// Note that the `provide_*` methods on `Demand` have short-circuit semantics: if an earlier
- /// method has successfully provided a value, then later methods will not get an opportunity to
- /// provide.
- ///
- /// # Examples
- ///
- /// Provides a reference to a field with type `String` as a `&str`, and a value of
- /// type `i32`.
- ///
- /// ```rust
- /// # #![feature(provide_any)]
- /// use std::any::{Provider, Demand};
- /// # struct SomeConcreteType { field: String, num_field: i32 }
- ///
- /// 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);
- /// }
- /// }
- /// ```
- #[unstable(feature = "provide_any", issue = "96024")]
- fn provide<'a>(&'a self, demand: &mut Demand<'a>);
-}
-
-/// Request a value from the `Provider`.
-///
-/// # Examples
-///
-/// Get a string value from a provider.
-///
-/// ```rust
-/// # #![feature(provide_any)]
-/// use std::any::{Provider, request_value};
-///
-/// fn get_string(provider: &impl Provider) -> String {
-/// request_value::<String>(provider).unwrap()
-/// }
-/// ```
-#[unstable(feature = "provide_any", issue = "96024")]
-pub fn request_value<'a, T>(provider: &'a (impl Provider + ?Sized)) -> Option<T>
-where
- T: 'static,
-{
- request_by_type_tag::<'a, tags::Value<T>>(provider)
-}
-
-/// Request a reference from the `Provider`.
-///
-/// # Examples
-///
-/// Get a string reference from a provider.
-///
-/// ```rust
-/// # #![feature(provide_any)]
-/// use std::any::{Provider, request_ref};
-///
-/// fn get_str(provider: &impl Provider) -> &str {
-/// request_ref::<str>(provider).unwrap()
-/// }
-/// ```
-#[unstable(feature = "provide_any", issue = "96024")]
-pub fn request_ref<'a, T>(provider: &'a (impl Provider + ?Sized)) -> Option<&'a T>
-where
- T: 'static + ?Sized,
-{
- request_by_type_tag::<'a, tags::Ref<tags::MaybeSizedValue<T>>>(provider)
-}
-
-/// Request a specific value by tag from the `Provider`.
-fn request_by_type_tag<'a, I>(provider: &'a (impl Provider + ?Sized)) -> Option<I::Reified>
-where
- I: tags::Type<'a>,
-{
- let mut tagged = TaggedOption::<'a, I>(None);
- provider.provide(tagged.as_demand());
- tagged.0
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Demand and its methods
-///////////////////////////////////////////////////////////////////////////////
-
-/// A helper object for providing data by type.
-///
-/// A data provider provides values by calling this type's provide methods.
-#[unstable(feature = "provide_any", issue = "96024")]
-#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
-pub struct Demand<'a>(dyn Erased<'a> + 'a);
-
-impl<'a> Demand<'a> {
- /// Create a new `&mut Demand` from a `&mut dyn Erased` trait object.
- fn new<'b>(erased: &'b mut (dyn Erased<'a> + 'a)) -> &'b mut Demand<'a> {
- // SAFETY: transmuting `&mut (dyn Erased<'a> + 'a)` to `&mut Demand<'a>` is safe since
- // `Demand` is repr(transparent).
- unsafe { &mut *(erased as *mut dyn Erased<'a> as *mut Demand<'a>) }
- }
-
- /// Provide a value or other type with only static lifetimes.
- ///
- /// # 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)]
- ///
- /// 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_with::<String>(|| self.field.clone());
- /// }
- /// }
- /// ```
- #[unstable(feature = "provide_any", issue = "96024")]
- 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. 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 { field: String }
- ///
- /// impl Provider for SomeConcreteType {
- /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
- /// demand.provide_ref::<str>(&self.field);
- /// }
- /// }
- /// ```
- #[unstable(feature = "provide_any", issue = "96024")]
- pub fn provide_ref<T: ?Sized + 'static>(&mut self, value: &'a T) -> &mut Self {
- 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
- I: tags::Type<'a>,
- {
- if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() {
- res.0 = Some(value);
- }
- self
- }
-
- /// Provide a value with the given `Type` tag, using a closure to prevent unnecessary work.
- fn provide_with<I>(&mut self, fulfil: impl FnOnce() -> I::Reified) -> &mut Self
- where
- I: tags::Type<'a>,
- {
- if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() {
- res.0 = Some(fulfil());
- }
- 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")]
-impl<'a> fmt::Debug for Demand<'a> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Demand").finish_non_exhaustive()
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Type tags
-///////////////////////////////////////////////////////////////////////////////
-
-mod tags {
- //! Type tags are used to identify a type using a separate value. This module includes type tags
- //! for some very common types.
- //!
- //! Currently type tags are not exposed to the user. But in the future, if you want to use the
- //! Provider API with more complex types (typically those including lifetime parameters), you
- //! will need to write your own tags.
-
- use crate::marker::PhantomData;
-
- /// This trait is implemented by specific tag types in order to allow
- /// describing a type which can be requested for a given lifetime `'a`.
- ///
- /// A few example implementations for type-driven tags can be found in this
- /// module, although crates may also implement their own tags for more
- /// complex types with internal lifetimes.
- pub trait Type<'a>: Sized + 'static {
- /// The type of values which may be tagged by this tag for the given
- /// lifetime.
- type Reified: 'a;
- }
-
- /// Similar to the [`Type`] trait, but represents a type which may be unsized (i.e., has a
- /// `?Sized` bound). E.g., `str`.
- pub trait MaybeSizedType<'a>: Sized + 'static {
- type Reified: 'a + ?Sized;
- }
-
- impl<'a, T: Type<'a>> MaybeSizedType<'a> for T {
- type Reified = T::Reified;
- }
-
- /// Type-based tag for types bounded by `'static`, i.e., with no borrowed elements.
- #[derive(Debug)]
- pub struct Value<T: 'static>(PhantomData<T>);
-
- impl<'a, T: 'static> Type<'a> for Value<T> {
- type Reified = T;
- }
-
- /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `?Sized` bound).
- #[derive(Debug)]
- pub struct MaybeSizedValue<T: ?Sized + 'static>(PhantomData<T>);
-
- impl<'a, T: ?Sized + 'static> MaybeSizedType<'a> for MaybeSizedValue<T> {
- type Reified = T;
- }
-
- /// Type-based tag for reference types (`&'a T`, where T is represented by
- /// `<I as MaybeSizedType<'a>>::Reified`.
- #[derive(Debug)]
- pub struct Ref<I>(PhantomData<I>);
-
- impl<'a, I: MaybeSizedType<'a>> Type<'a> for Ref<I> {
- type Reified = &'a I::Reified;
- }
-}
-
-/// An `Option` with a type tag `I`.
-///
-/// Since this struct implements `Erased`, the type can be erased to make a dynamically typed
-/// option. The type can be checked dynamically using `Erased::tag_id` and since this is statically
-/// checked for the concrete type, there is some degree of type safety.
-#[repr(transparent)]
-struct TaggedOption<'a, I: tags::Type<'a>>(Option<I::Reified>);
-
-impl<'a, I: tags::Type<'a>> TaggedOption<'a, I> {
- fn as_demand(&mut self) -> &mut Demand<'a> {
- Demand::new(self as &mut (dyn Erased<'a> + 'a))
- }
-}
-
-/// Represents a type-erased but identifiable object.
-///
-/// This trait is exclusively implemented by the `TaggedOption` type.
-unsafe trait Erased<'a>: 'a {
- /// The `TypeId` of the erased type.
- fn tag_id(&self) -> TypeId;
-}
-
-unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {
- fn tag_id(&self) -> TypeId {
- TypeId::of::<I>()
- }
-}
-
-#[unstable(feature = "provide_any", issue = "96024")]
-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>,
- {
- if self.tag_id() == TypeId::of::<I>() {
- // SAFETY: Just checked whether we're pointing to an I.
- Some(unsafe { &mut *(self as *mut Self).cast::<TaggedOption<'a, I>>() })
- } else {
- None
- }
- }
-}
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 76b3589b9..ebd4a8c05 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -925,7 +925,7 @@ fn iter_next_chunk_erased<T>(
// so we need to defuse the guard instead of using `?`.
let initialized = guard.initialized;
mem::forget(guard);
- return Err(initialized)
+ return Err(initialized);
};
// SAFETY: The loop condition ensures we have space to push the item
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index f093a0990..5378b210e 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -518,14 +518,14 @@ impl AsciiChar {
/// Gets this ASCII character as a byte.
#[unstable(feature = "ascii_char", issue = "110998")]
#[inline]
- pub const fn as_u8(self) -> u8 {
+ pub const fn to_u8(self) -> u8 {
self as u8
}
/// Gets this ASCII character as a `char` Unicode Scalar Value.
#[unstable(feature = "ascii_char", issue = "110998")]
#[inline]
- pub const fn as_char(self) -> char {
+ pub const fn to_char(self) -> char {
self as u8 as char
}
diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs
index efc9ada38..bc026d0a4 100644
--- a/library/core/src/borrow.rs
+++ b/library/core/src/borrow.rs
@@ -22,7 +22,7 @@
/// Types express that they can be borrowed as some type `T` by implementing
/// `Borrow<T>`, providing a reference to a `T` in the trait’s
/// [`borrow`] method. A type is free to borrow as several different types.
-/// If it wishes to mutably borrow as the type – allowing the underlying data
+/// If it wishes to mutably borrow as the type, allowing the underlying data
/// to be modified, it can additionally implement [`BorrowMut<T>`].
///
/// Further, when providing implementations for additional traits, it needs
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 909b32547..bf4c682d3 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1893,7 +1893,8 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
/// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
/// same memory layout, the following is not allowed and undefined behavior:
///
-/// ```rust,no_run
+#[cfg_attr(bootstrap, doc = "```rust,no_run")]
+#[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")]
/// # use std::cell::UnsafeCell;
/// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
/// let t = ptr as *const UnsafeCell<T> as *mut T;
diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs
index 5f06a7b07..2e8534f65 100644
--- a/library/core/src/cell/once.rs
+++ b/library/core/src/cell/once.rs
@@ -250,10 +250,12 @@ impl<T> Default for OnceCell<T> {
#[stable(feature = "once_cell", since = "1.70.0")]
impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut d = f.debug_tuple("OnceCell");
match self.get() {
- Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
- None => f.write_str("OnceCell(Uninit)"),
- }
+ Some(v) => d.field(v),
+ None => d.field(&format_args!("<uninit>")),
+ };
+ d.finish()
}
}
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index a6d6230d3..d7ca9c22d 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -86,6 +86,46 @@
/// }
/// ```
///
+/// If we `derive`:
+///
+/// ```
+/// #[derive(Copy, Clone)]
+/// struct Generate<T>(fn() -> T);
+/// ```
+///
+/// the auto-derived implementations will have unnecessary `T: Copy` and `T: Clone` bounds:
+///
+/// ```
+/// # struct Generate<T>(fn() -> T);
+///
+/// // Automatically derived
+/// impl<T: Copy> Copy for Generate<T> { }
+///
+/// // Automatically derived
+/// impl<T: Clone> Clone for Generate<T> {
+/// fn clone(&self) -> Generate<T> {
+/// Generate(Clone::clone(&self.0))
+/// }
+/// }
+/// ```
+///
+/// The bounds are unnecessary because clearly the function itself should be
+/// copy- and cloneable even if its return type is not:
+///
+/// ```compile_fail,E0599
+/// #[derive(Copy, Clone)]
+/// struct Generate<T>(fn() -> T);
+///
+/// struct NotCloneable;
+///
+/// fn generate_not_cloneable() -> NotCloneable {
+/// NotCloneable
+/// }
+///
+/// Generate(generate_not_cloneable).clone(); // error: trait bounds were not satisfied
+/// // Note: With the manual implementations the above line will compile.
+/// ```
+///
/// ## Additional implementors
///
/// In addition to the [implementors listed below][impls],
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index faf48ae57..3c127efb3 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -1406,6 +1406,22 @@ mod impls {
_ => unsafe { unreachable_unchecked() },
}
}
+
+ #[inline]
+ fn min(self, other: bool) -> bool {
+ self & other
+ }
+
+ #[inline]
+ fn max(self, other: bool) -> bool {
+ self | other
+ }
+
+ #[inline]
+ fn clamp(self, min: bool, max: bool) -> bool {
+ assert!(min <= max);
+ self.max(min).min(max)
+ }
}
ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index 1f7be85d3..5242e97eb 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -133,51 +133,6 @@ pub trait Default: Sized {
fn default() -> Self;
}
-/// Return the default value of a type according to the `Default` trait.
-///
-/// The type to return is inferred from context; this is equivalent to
-/// `Default::default()` but shorter to type.
-///
-/// For example:
-/// ```
-/// #![feature(default_free_fn)]
-///
-/// use std::default::default;
-///
-/// #[derive(Default)]
-/// struct AppConfig {
-/// foo: FooConfig,
-/// bar: BarConfig,
-/// }
-///
-/// #[derive(Default)]
-/// struct FooConfig {
-/// foo: i32,
-/// }
-///
-/// #[derive(Default)]
-/// struct BarConfig {
-/// bar: f32,
-/// baz: u8,
-/// }
-///
-/// fn main() {
-/// let options = AppConfig {
-/// foo: default(),
-/// bar: BarConfig {
-/// bar: 10.1,
-/// ..default()
-/// },
-/// };
-/// }
-/// ```
-#[unstable(feature = "default_free_fn", issue = "73014")]
-#[must_use]
-#[inline]
-pub fn default<T: Default>() -> T {
- Default::default()
-}
-
/// Derive macro generating an impl of the trait `Default`.
#[rustc_builtin_macro(Default, attributes(default))]
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
diff --git a/library/core/src/error.md b/library/core/src/error.md
index 78808d489..7771b8adc 100644
--- a/library/core/src/error.md
+++ b/library/core/src/error.md
@@ -93,7 +93,8 @@ 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
+thread 'main' panicked at src/main.rs:4:6:
+env variable `IMPORTANT_PATH` is not set: NotPresent
```
In this example we end up mentioning that an env variable is not set,
@@ -109,7 +110,8 @@ 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
+thread 'main' panicked at src/main.rs:4:6:
+env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent
```
In this example we are communicating not only the name of the
diff --git a/library/core/src/error.rs b/library/core/src/error.rs
index 11cb08275..1170221c1 100644
--- a/library/core/src/error.rs
+++ b/library/core/src/error.rs
@@ -4,8 +4,8 @@
#[cfg(test)]
mod tests;
-use crate::any::{Demand, Provider, TypeId};
-use crate::fmt::{Debug, Display};
+use crate::any::TypeId;
+use crate::fmt::{Debug, Display, Formatter, Result};
/// `Error` is a trait representing the basic expectations for error values,
/// i.e., values of type `E` in [`Result<T, E>`].
@@ -123,16 +123,21 @@ pub trait Error: Debug + Display {
/// Provides type based access to context intended for error reports.
///
- /// Used in conjunction with [`Demand::provide_value`] and [`Demand::provide_ref`] to extract
+ /// Used in conjunction with [`Request::provide_value`] and [`Request::provide_ref`] to extract
/// references to member variables from `dyn Error` trait objects.
///
/// # Example
///
/// ```rust
- /// #![feature(provide_any)]
/// #![feature(error_generic_member_access)]
+ /// #![feature(error_in_core)]
/// use core::fmt;
- /// use core::any::Demand;
+ /// use core::error::{request_ref, Request};
+ ///
+ /// #[derive(Debug)]
+ /// enum MyLittleTeaPot {
+ /// Empty,
+ /// }
///
/// #[derive(Debug)]
/// struct MyBacktrace {
@@ -147,21 +152,7 @@ pub trait Error: Debug + Display {
/// }
///
/// #[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,
/// }
///
@@ -172,38 +163,26 @@ pub trait Error: Debug + Display {
/// }
///
/// 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 provide<'a>(&'a self, request: &mut Request<'a>) {
+ /// request
+ /// .provide_ref::<MyBacktrace>(&self.backtrace);
/// }
/// }
///
/// fn main() {
/// let backtrace = MyBacktrace::new();
- /// let source = SourceError {};
- /// let error = Error { source, backtrace };
+ /// let error = Error { backtrace };
/// let dyn_error = &error as &dyn std::error::Error;
- /// let backtrace_ref = dyn_error.request_ref::<MyBacktrace>().unwrap();
+ /// let backtrace_ref = request_ref::<MyBacktrace>(dyn_error).unwrap();
///
/// assert!(core::ptr::eq(&error.backtrace, backtrace_ref));
+ /// assert!(request_ref::<MyLittleTeaPot>(dyn_error).is_none());
/// }
/// ```
#[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)
- }
+ fn provide<'a>(&'a self, request: &mut Request<'a>) {}
}
-
mod private {
// This is a hack to prevent `type_id` from being overridden by `Error`
// implementations, since that can enable unsound downcasting.
@@ -215,20 +194,6 @@ mod private {
#[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`.
@@ -293,18 +258,6 @@ impl dyn Error + 'static + Send {
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 {
@@ -328,18 +281,6 @@ impl dyn Error + 'static + Send + Sync {
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 {
@@ -412,6 +353,654 @@ impl dyn Error {
}
}
+/// Request a value of type `T` from the given `impl Error`.
+///
+/// # Examples
+///
+/// Get a string value from an error.
+///
+/// ```rust
+/// # #![feature(error_generic_member_access)]
+/// # #![feature(error_in_core)]
+/// use std::error::Error;
+/// use core::error::request_value;
+///
+/// fn get_string(err: &impl Error) -> String {
+/// request_value::<String>(err).unwrap()
+/// }
+/// ```
+#[unstable(feature = "error_generic_member_access", issue = "99301")]
+pub fn request_value<'a, T>(err: &'a (impl Error + ?Sized)) -> Option<T>
+where
+ T: 'static,
+{
+ request_by_type_tag::<'a, tags::Value<T>>(err)
+}
+
+/// Request a reference of type `T` from the given `impl Error`.
+///
+/// # Examples
+///
+/// Get a string reference from an error.
+///
+/// ```rust
+/// # #![feature(error_generic_member_access)]
+/// # #![feature(error_in_core)]
+/// use core::error::Error;
+/// use core::error::request_ref;
+///
+/// fn get_str(err: &impl Error) -> &str {
+/// request_ref::<str>(err).unwrap()
+/// }
+/// ```
+#[unstable(feature = "error_generic_member_access", issue = "99301")]
+pub fn request_ref<'a, T>(err: &'a (impl Error + ?Sized)) -> Option<&'a T>
+where
+ T: 'static + ?Sized,
+{
+ request_by_type_tag::<'a, tags::Ref<tags::MaybeSizedValue<T>>>(err)
+}
+
+/// Request a specific value by tag from the `Error`.
+fn request_by_type_tag<'a, I>(err: &'a (impl Error + ?Sized)) -> Option<I::Reified>
+where
+ I: tags::Type<'a>,
+{
+ let mut tagged = TaggedOption::<'a, I>(None);
+ err.provide(tagged.as_request());
+ tagged.0
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Request and its methods
+///////////////////////////////////////////////////////////////////////////////
+
+/// `Request` supports generic, type-driven access to data. It's use is currently restricted to the
+/// standard library in cases where trait authors wish to allow trait implementors to share generic
+/// information across trait boundaries. The motivating and prototypical use case is
+/// `core::error::Error` which would otherwise require a method per concrete type (eg.
+/// `std::backtrace::Backtrace` instance that implementors want to expose to users).
+///
+/// # Data flow
+///
+/// To describe the intended data flow for Request objects, let's consider two conceptual users
+/// separated by API boundaries:
+///
+/// * Consumer - the consumer requests objects using a Request instance; eg a crate that offers
+/// fancy `Error`/`Result` reporting to users wants to request a Backtrace from a given `dyn Error`.
+///
+/// * Producer - the producer provides objects when requested via Request; eg. a library with an
+/// an `Error` implementation that automatically captures backtraces at the time instances are
+/// created.
+///
+/// The consumer only needs to know where to submit their request and are expected to handle the
+/// request not being fulfilled by the use of `Option<T>` in the responses offered by the producer.
+///
+/// * A Producer initializes the value of one of its fields of a specific type. (or is otherwise
+/// prepared to generate a value requested). eg, `backtrace::Backtrace` or
+/// `std::backtrace::Backtrace`
+/// * A Consumer requests an object of a specific type (say `std::backtrace::Backtrace). In the case
+/// of a `dyn Error` trait object (the Producer), there are methods called `request_ref` and
+/// `request_value` are available to simplify obtaining an ``Option<T>`` for a given type. * The
+/// Producer, when requested, populates the given Request object which is given as a mutable
+/// reference.
+/// * The Consumer extracts a value or reference to the requested type from the `Request` object
+/// wrapped in an `Option<T>`; in the case of `dyn Error` the aforementioned `request_ref` and `
+/// request_value` methods mean that `dyn Error` users don't have to deal with the `Request` type at
+/// all (but `Error` implementors do). The `None` case of the `Option` suggests only that the
+/// Producer cannot currently offer an instance of the requested type, not it can't or never will.
+///
+/// # Examples
+///
+/// The best way to demonstrate this is using an example implementation of `Error`'s `provide` trait
+/// method:
+///
+/// ```
+/// #![feature(error_generic_member_access)]
+/// #![feature(error_in_core)]
+/// use core::fmt;
+/// use core::error::Request;
+/// use core::error::request_ref;
+///
+/// #[derive(Debug)]
+/// enum MyLittleTeaPot {
+/// Empty,
+/// }
+///
+/// #[derive(Debug)]
+/// struct MyBacktrace {
+/// // ...
+/// }
+///
+/// impl MyBacktrace {
+/// fn new() -> MyBacktrace {
+/// // ...
+/// # MyBacktrace {}
+/// }
+/// }
+///
+/// #[derive(Debug)]
+/// struct Error {
+/// 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, request: &mut Request<'a>) {
+/// request
+/// .provide_ref::<MyBacktrace>(&self.backtrace);
+/// }
+/// }
+///
+/// fn main() {
+/// let backtrace = MyBacktrace::new();
+/// let error = Error { backtrace };
+/// let dyn_error = &error as &dyn std::error::Error;
+/// let backtrace_ref = request_ref::<MyBacktrace>(dyn_error).unwrap();
+///
+/// assert!(core::ptr::eq(&error.backtrace, backtrace_ref));
+/// assert!(request_ref::<MyLittleTeaPot>(dyn_error).is_none());
+/// }
+/// ```
+///
+#[unstable(feature = "error_generic_member_access", issue = "99301")]
+#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
+pub struct Request<'a>(dyn Erased<'a> + 'a);
+
+impl<'a> Request<'a> {
+ /// Create a new `&mut Request` from a `&mut dyn Erased` trait object.
+ fn new<'b>(erased: &'b mut (dyn Erased<'a> + 'a)) -> &'b mut Request<'a> {
+ // SAFETY: transmuting `&mut (dyn Erased<'a> + 'a)` to `&mut Request<'a>` is safe since
+ // `Request` is repr(transparent).
+ unsafe { &mut *(erased as *mut dyn Erased<'a> as *mut Request<'a>) }
+ }
+
+ /// Provide a value or other type with only static lifetimes.
+ ///
+ /// # Examples
+ ///
+ /// Provides an `u8`.
+ ///
+ /// ```rust
+ /// #![feature(error_generic_member_access)]
+ /// #![feature(error_in_core)]
+ ///
+ /// use core::error::Request;
+ ///
+ /// #[derive(Debug)]
+ /// struct SomeConcreteType { field: u8 }
+ ///
+ /// impl std::fmt::Display for SomeConcreteType {
+ /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ /// write!(f, "{} failed", self.field)
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for SomeConcreteType {
+ /// fn provide<'a>(&'a self, request: &mut Request<'a>) {
+ /// request.provide_value::<u8>(self.field);
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ 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(error_generic_member_access)]
+ /// #![feature(error_in_core)]
+ ///
+ /// use core::error::Request;
+ ///
+ /// #[derive(Debug)]
+ /// struct SomeConcreteType { field: String }
+ ///
+ /// impl std::fmt::Display for SomeConcreteType {
+ /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ /// write!(f, "{} failed", self.field)
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for SomeConcreteType {
+ /// fn provide<'a>(&'a self, request: &mut Request<'a>) {
+ /// request.provide_value_with::<String>(|| self.field.clone());
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ 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. The referee type must be bounded by `'static`,
+ /// but may be unsized.
+ ///
+ /// # Examples
+ ///
+ /// Provides a reference to a field as a `&str`.
+ ///
+ /// ```rust
+ /// #![feature(error_generic_member_access)]
+ /// #![feature(error_in_core)]
+ ///
+ /// use core::error::Request;
+ ///
+ /// #[derive(Debug)]
+ /// struct SomeConcreteType { field: String }
+ ///
+ /// impl std::fmt::Display for SomeConcreteType {
+ /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ /// write!(f, "{} failed", self.field)
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for SomeConcreteType {
+ /// fn provide<'a>(&'a self, request: &mut Request<'a>) {
+ /// request.provide_ref::<str>(&self.field);
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ pub fn provide_ref<T: ?Sized + 'static>(&mut self, value: &'a T) -> &mut Self {
+ 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(error_generic_member_access)]
+ /// #![feature(error_in_core)]
+ ///
+ /// use core::error::Request;
+ ///
+ /// #[derive(Debug)]
+ /// struct SomeConcreteType { business: String, party: String }
+ /// fn today_is_a_weekday() -> bool { true }
+ ///
+ /// impl std::fmt::Display for SomeConcreteType {
+ /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ /// write!(f, "{} failed", self.business)
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for SomeConcreteType {
+ /// fn provide<'a>(&'a self, request: &mut Request<'a>) {
+ /// request.provide_ref_with::<str>(|| {
+ /// if today_is_a_weekday() {
+ /// &self.business
+ /// } else {
+ /// &self.party
+ /// }
+ /// });
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ 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
+ I: tags::Type<'a>,
+ {
+ if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() {
+ res.0 = Some(value);
+ }
+ self
+ }
+
+ /// Provide a value with the given `Type` tag, using a closure to prevent unnecessary work.
+ fn provide_with<I>(&mut self, fulfil: impl FnOnce() -> I::Reified) -> &mut Self
+ where
+ I: tags::Type<'a>,
+ {
+ if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() {
+ res.0 = Some(fulfil());
+ }
+ self
+ }
+
+ /// Check if the `Request` 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(error_generic_member_access)]
+ /// #![feature(error_in_core)]
+ ///
+ /// use core::error::Request;
+ /// use core::error::request_value;
+ ///
+ /// #[derive(Debug)]
+ /// struct Parent(Option<u8>);
+ ///
+ /// impl std::fmt::Display for Parent {
+ /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ /// write!(f, "a parent failed")
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for Parent {
+ /// fn provide<'a>(&'a self, request: &mut Request<'a>) {
+ /// if let Some(v) = self.0 {
+ /// request.provide_value::<u8>(v);
+ /// }
+ /// }
+ /// }
+ ///
+ /// #[derive(Debug)]
+ /// 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 std::fmt::Display for Child {
+ /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ /// write!(f, "child failed: \n because of parent: {}", self.parent)
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for Child {
+ /// fn provide<'a>(&'a self, request: &mut Request<'a>) {
+ /// // In general, we don't know if this call will provide
+ /// // an `u8` value or not...
+ /// self.parent.provide(request);
+ ///
+ /// // ...so we check to see if the `u8` is needed before
+ /// // we run our expensive computation.
+ /// if request.would_be_satisfied_by_value_of::<u8>() {
+ /// if let Some(v) = self.an_expensive_computation() {
+ /// request.provide_value::<u8>(v);
+ /// }
+ /// }
+ ///
+ /// // The request will be satisfied now, regardless of if
+ /// // the parent provided the value or we did.
+ /// assert!(!request.would_be_satisfied_by_value_of::<u8>());
+ /// }
+ /// }
+ ///
+ /// let parent = Parent(Some(42));
+ /// let child = Child { parent };
+ /// assert_eq!(Some(42), request_value::<u8>(&child));
+ ///
+ /// let parent = Parent(None);
+ /// let child = Child { parent };
+ /// assert_eq!(Some(99), request_value::<u8>(&child));
+ ///
+ /// ```
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ 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 `Request` 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(error_generic_member_access)]
+ /// #![feature(error_in_core)]
+ ///
+ /// use core::error::Request;
+ /// use core::error::request_ref;
+ ///
+ /// #[derive(Debug)]
+ /// struct Parent(Option<String>);
+ ///
+ /// impl std::fmt::Display for Parent {
+ /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ /// write!(f, "a parent failed")
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for Parent {
+ /// fn provide<'a>(&'a self, request: &mut Request<'a>) {
+ /// if let Some(v) = &self.0 {
+ /// request.provide_ref::<str>(v);
+ /// }
+ /// }
+ /// }
+ ///
+ /// #[derive(Debug)]
+ /// 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 std::fmt::Display for Child {
+ /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ /// write!(f, "{} failed: \n {}", self.name, self.parent)
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for Child {
+ /// fn provide<'a>(&'a self, request: &mut Request<'a>) {
+ /// // In general, we don't know if this call will provide
+ /// // a `str` reference or not...
+ /// self.parent.provide(request);
+ ///
+ /// // ...so we check to see if the `&str` is needed before
+ /// // we run our expensive computation.
+ /// if request.would_be_satisfied_by_ref_of::<str>() {
+ /// if let Some(v) = self.an_expensive_computation() {
+ /// request.provide_ref::<str>(v);
+ /// }
+ /// }
+ ///
+ /// // The request will be satisfied now, regardless of if
+ /// // the parent provided the reference or we did.
+ /// assert!(!request.would_be_satisfied_by_ref_of::<str>());
+ /// }
+ /// }
+ ///
+ /// let parent = Parent(Some("parent".into()));
+ /// let child = Child { parent, name: "child".into() };
+ /// assert_eq!(Some("parent"), request_ref::<str>(&child));
+ ///
+ /// let parent = Parent(None);
+ /// let child = Child { parent, name: "child".into() };
+ /// assert_eq!(Some("child"), request_ref::<str>(&child));
+ /// ```
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ 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 = "error_generic_member_access", issue = "99301")]
+impl<'a> Debug for Request<'a> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ f.debug_struct("Request").finish_non_exhaustive()
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Type tags
+///////////////////////////////////////////////////////////////////////////////
+
+pub(crate) mod tags {
+ //! Type tags are used to identify a type using a separate value. This module includes type tags
+ //! for some very common types.
+ //!
+ //! Currently type tags are not exposed to the user. But in the future, if you want to use the
+ //! Request API with more complex types (typically those including lifetime parameters), you
+ //! will need to write your own tags.
+
+ use crate::marker::PhantomData;
+
+ /// This trait is implemented by specific tag types in order to allow
+ /// describing a type which can be requested for a given lifetime `'a`.
+ ///
+ /// A few example implementations for type-driven tags can be found in this
+ /// module, although crates may also implement their own tags for more
+ /// complex types with internal lifetimes.
+ pub(crate) trait Type<'a>: Sized + 'static {
+ /// The type of values which may be tagged by this tag for the given
+ /// lifetime.
+ type Reified: 'a;
+ }
+
+ /// Similar to the [`Type`] trait, but represents a type which may be unsized (i.e., has a
+ /// `?Sized` bound). E.g., `str`.
+ pub(crate) trait MaybeSizedType<'a>: Sized + 'static {
+ type Reified: 'a + ?Sized;
+ }
+
+ impl<'a, T: Type<'a>> MaybeSizedType<'a> for T {
+ type Reified = T::Reified;
+ }
+
+ /// Type-based tag for types bounded by `'static`, i.e., with no borrowed elements.
+ #[derive(Debug)]
+ pub(crate) struct Value<T: 'static>(PhantomData<T>);
+
+ impl<'a, T: 'static> Type<'a> for Value<T> {
+ type Reified = T;
+ }
+
+ /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `?Sized` bound).
+ #[derive(Debug)]
+ pub(crate) struct MaybeSizedValue<T: ?Sized + 'static>(PhantomData<T>);
+
+ impl<'a, T: ?Sized + 'static> MaybeSizedType<'a> for MaybeSizedValue<T> {
+ type Reified = T;
+ }
+
+ /// Type-based tag for reference types (`&'a T`, where T is represented by
+ /// `<I as MaybeSizedType<'a>>::Reified`.
+ #[derive(Debug)]
+ pub(crate) struct Ref<I>(PhantomData<I>);
+
+ impl<'a, I: MaybeSizedType<'a>> Type<'a> for Ref<I> {
+ type Reified = &'a I::Reified;
+ }
+}
+
+/// An `Option` with a type tag `I`.
+///
+/// Since this struct implements `Erased`, the type can be erased to make a dynamically typed
+/// option. The type can be checked dynamically using `Erased::tag_id` and since this is statically
+/// checked for the concrete type, there is some degree of type safety.
+#[repr(transparent)]
+pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option<I::Reified>);
+
+impl<'a, I: tags::Type<'a>> TaggedOption<'a, I> {
+ pub(crate) fn as_request(&mut self) -> &mut Request<'a> {
+ Request::new(self as &mut (dyn Erased<'a> + 'a))
+ }
+}
+
+/// Represents a type-erased but identifiable object.
+///
+/// This trait is exclusively implemented by the `TaggedOption` type.
+unsafe trait Erased<'a>: 'a {
+ /// The `TypeId` of the erased type.
+ fn tag_id(&self) -> TypeId;
+}
+
+unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {
+ fn tag_id(&self) -> TypeId {
+ TypeId::of::<I>()
+ }
+}
+
+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>,
+ {
+ if self.tag_id() == TypeId::of::<I>() {
+ // SAFETY: Just checked whether we're pointing to an I.
+ Some(unsafe { &mut *(self as *mut Self).cast::<TaggedOption<'a, I>>() })
+ } else {
+ None
+ }
+ }
+}
+
/// An iterator over an [`Error`] and its sources.
///
/// If you want to omit the initial error and only process
@@ -449,8 +1038,8 @@ impl<'a, T: Error + ?Sized> Error for &'a T {
Error::source(&**self)
}
- fn provide<'b>(&'b self, demand: &mut Demand<'b>) {
- Error::provide(&**self, demand);
+ fn provide<'b>(&'b self, request: &mut Request<'b>) {
+ Error::provide(&**self, request);
}
}
diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs
index 3d471419b..24bb9ad1a 100644
--- a/library/core/src/escape.rs
+++ b/library/core/src/escape.rs
@@ -95,11 +95,11 @@ impl<const N: usize> EscapeIterInner<N> {
}
pub fn next(&mut self) -> Option<u8> {
- self.alive.next().map(|i| self.data[usize::from(i)].as_u8())
+ self.alive.next().map(|i| self.data[usize::from(i)].to_u8())
}
pub fn next_back(&mut self) -> Option<u8> {
- self.alive.next_back().map(|i| self.data[usize::from(i)].as_u8())
+ self.alive.next_back().map(|i| self.data[usize::from(i)].to_u8())
}
pub fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 39f795c1f..163a65c90 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -20,10 +20,10 @@ use crate::str;
/// in each pair are borrowed references; the latter are owned
/// strings.
///
-/// Note that this structure is **not** `repr(C)` and is not recommended to be
-/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
-/// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide
-/// a safe interface to other consumers.
+/// Note that this structure does **not** have a guaranteed layout (the `repr(transparent)`
+/// notwithstanding) and is not recommended to be placed in the signatures of FFI functions.
+/// Instead, safe wrappers of FFI functions may leverage the unsafe [`CStr::from_ptr`] constructor
+/// to provide a safe interface to other consumers.
///
/// [`CString`]: ../../std/ffi/struct.CString.html
/// [`String`]: ../../std/string/struct.String.html
@@ -82,12 +82,12 @@ use crate::str;
#[stable(feature = "core_c_str", since = "1.64.0")]
#[rustc_has_incoherent_inherent_impls]
#[lang = "CStr"]
-// FIXME:
// `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
// on `CStr` being layout-compatible with `[u8]`.
-// When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`.
-// Anyway, `CStr` representation and layout are considered implementation detail, are
-// not documented and must not be relied upon.
+// However, `CStr` layout is considered an implementation detail and must not be relied upon. We
+// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
+// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
+#[cfg_attr(not(doc), repr(transparent))]
pub struct CStr {
// FIXME: this should not be represented with a DST slice but rather with
// just a raw `c_char` along with some form of marker to make
@@ -197,8 +197,8 @@ impl CStr {
///
/// This function will wrap the provided `ptr` with a `CStr` wrapper, which
/// allows inspection and interoperation of non-owned C strings. The total
- /// size of the raw C string must be smaller than `isize::MAX` **bytes**
- /// in memory due to calling the `slice::from_raw_parts` function.
+ /// size of the terminated buffer must be smaller than [`isize::MAX`] **bytes**
+ /// in memory (a restriction from [`slice::from_raw_parts`]).
///
/// # Safety
///
@@ -253,10 +253,10 @@ impl CStr {
/// ```
///
/// [valid]: core::ptr#safety
- #[inline]
+ #[inline] // inline is necessary for codegen to see strlen.
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "101719")]
+ #[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")]
pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
// SAFETY: The caller has provided a pointer that points to a valid C
// string with a NUL terminator of size less than `isize::MAX`, whose
@@ -280,6 +280,8 @@ impl CStr {
len
}
+ // `inline` is necessary for codegen to see strlen.
+ #[inline]
fn strlen_rt(s: *const c_char) -> usize {
extern "C" {
/// Provided by libc or compiler_builtins.
@@ -295,11 +297,11 @@ impl CStr {
}
}
- /// Creates a C string wrapper from a byte slice.
+ /// Creates a C string wrapper from a byte slice with any number of nuls.
///
/// This method will create a `CStr` from any byte slice that contains at
- /// least one nul byte. The caller does not need to know or specify where
- /// the nul byte is located.
+ /// least one nul byte. Unlike with [`CStr::from_bytes_with_nul`], the caller
+ /// does not need to know where the nul byte is located.
///
/// If the first byte is a nul character, this method will return an
/// empty `CStr`. If multiple nul characters are present, the `CStr` will
@@ -341,7 +343,8 @@ impl CStr {
}
}
- /// Creates a C string wrapper from a byte slice.
+ /// Creates a C string wrapper from a byte slice with exactly one nul
+ /// terminator.
///
/// This function will cast the provided `bytes` to a `CStr`
/// wrapper after ensuring that the byte slice is nul-terminated
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index 0488c8076..b2c9a0800 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -52,11 +52,6 @@ macro_rules! type_alias {
}
type_alias! { "c_char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char;
-// Make this type alias appear cfg-dependent so that Clippy does not suggest
-// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed
-// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093
-// is fixed.
-#[cfg(all())]
#[doc(cfg(all()))] }
type_alias! { "c_schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
@@ -115,7 +110,8 @@ mod c_char_definition {
target_arch = "powerpc64",
target_arch = "s390x",
target_arch = "riscv64",
- target_arch = "riscv32"
+ target_arch = "riscv32",
+ target_arch = "csky"
)
),
all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs
index 36f49d51c..d2c9f9800 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -518,7 +518,7 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_set()
/// .entries(self.0.iter())
- /// .finish() // Ends the struct formatting.
+ /// .finish() // Ends the set formatting.
/// }
/// }
///
@@ -648,7 +648,7 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_list()
/// .entries(self.0.iter())
- /// .finish() // Ends the struct formatting.
+ /// .finish() // Ends the list formatting.
/// }
/// }
///
@@ -905,7 +905,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_map()
/// .entries(self.0.iter().map(|&(ref k, ref v)| (k, v)))
- /// .finish() // Ends the struct formatting.
+ /// .finish() // Ends the map formatting.
/// }
/// }
///
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 1786b309c..9ce6093f1 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2521,22 +2521,12 @@ impl<T: Copy + Debug> Debug for Cell<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Debug> Debug for RefCell<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let mut d = f.debug_struct("RefCell");
match self.try_borrow() {
- Ok(borrow) => f.debug_struct("RefCell").field("value", &borrow).finish(),
- Err(_) => {
- // The RefCell is mutably borrowed so we can't look at its value
- // here. Show a placeholder instead.
- struct BorrowedPlaceholder;
-
- impl Debug for BorrowedPlaceholder {
- fn fmt(&self, f: &mut Formatter<'_>) -> Result {
- f.write_str("<borrowed>")
- }
- }
-
- f.debug_struct("RefCell").field("value", &BorrowedPlaceholder).finish()
- }
- }
+ Ok(borrow) => d.field("value", &borrow),
+ Err(_) => d.field("value", &format_args!("<borrowed>")),
+ };
+ d.finish()
}
}
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 5a9a7013a..676d4f2f3 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -9,7 +9,7 @@
//! This includes changes in the stability of the constness.
//!
//! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
-//! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs> to
+//! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics> to
//! <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs> and add a
//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
//!
@@ -1057,23 +1057,6 @@ extern "rust-intrinsic" {
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
#[rustc_safe_intrinsic]
#[rustc_nounwind]
- #[cfg(bootstrap)]
- pub fn type_id<T: ?Sized + 'static>() -> u64;
-
- /// Gets an identifier which is globally unique to the specified type. This
- /// function will return the same value for a type regardless of whichever
- /// crate it is invoked in.
- ///
- /// 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.
- ///
- /// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
- #[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
- #[rustc_safe_intrinsic]
- #[rustc_nounwind]
- #[cfg(not(bootstrap))]
pub fn type_id<T: ?Sized + 'static>() -> u128;
/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited:
@@ -2402,6 +2385,25 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
pub fn raw_eq<T>(a: &T, b: &T) -> bool;
+ /// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)`
+ /// as unsigned bytes, returning negative if `left` is less, zero if all the
+ /// bytes match, or positive if `right` is greater.
+ ///
+ /// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`.
+ ///
+ /// # Safety
+ ///
+ /// `left` and `right` must each be [valid] for reads of `bytes` bytes.
+ ///
+ /// Note that this applies to the whole range, not just until the first byte
+ /// that differs. That allows optimizations that can read in large chunks.
+ ///
+ /// [valid]: crate::ptr#safety
+ #[cfg(not(bootstrap))]
+ #[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")]
+ #[rustc_nounwind]
+ pub fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32;
+
/// See documentation of [`std::hint::black_box`] for details.
///
/// [`std::hint::black_box`]: crate::hint::black_box
@@ -2541,12 +2543,14 @@ pub(crate) use assert_unsafe_precondition;
/// Checks whether `ptr` is properly aligned with respect to
/// `align_of::<T>()`.
+#[inline]
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
!ptr.is_null() && ptr.is_aligned()
}
/// Checks whether an allocation of `len` instances of `T` exceeds
/// the maximum allowed allocation size.
+#[inline]
pub(crate) fn is_valid_allocation_size<T>(len: usize) -> bool {
let max_len = const {
let size = crate::mem::size_of::<T>();
@@ -2557,6 +2561,7 @@ pub(crate) fn is_valid_allocation_size<T>(len: usize) -> bool {
/// Checks whether the regions of memory starting at `src` and `dst` of size
/// `count * size_of::<T>()` do *not* overlap.
+#[inline]
pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
let src_usize = src.addr();
let dst_usize = dst.addr();
@@ -2839,3 +2844,18 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
write_bytes(dst, val, count)
}
}
+
+/// Backfill for bootstrap
+#[cfg(bootstrap)]
+pub unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32 {
+ extern "C" {
+ fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> crate::ffi::c_int;
+ }
+
+ if bytes != 0 {
+ // SAFETY: Since bytes is non-zero, the caller has met `memcmp`'s requirements.
+ unsafe { memcmp(left, right, bytes).into() }
+ } else {
+ 0
+ }
+}
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 5944a0de1..ef0a2fd4e 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -14,6 +14,7 @@
//!
//! ```rust
//! #![feature(core_intrinsics, custom_mir)]
+#![cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")]
//!
//! use core::intrinsics::mir::*;
//!
@@ -63,6 +64,7 @@
//!
//! ```rust
//! #![feature(core_intrinsics, custom_mir)]
+#![cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")]
//!
//! use core::intrinsics::mir::*;
//!
@@ -102,17 +104,18 @@
//! }
//!
//! #[custom_mir(dialect = "runtime", phase = "optimized")]
+#![cfg_attr(bootstrap, doc = "#[cfg(any())]")] // disable the following function in doctests when `bootstrap` is set
//! fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
//! mir!(
-//! let unused;
+//! let _unused;
//! let popped;
//!
//! {
-//! Call(unused, pop, Vec::push(v, value))
+//! Call(_unused = Vec::push(v, value), pop)
//! }
//!
//! pop = {
-//! Call(popped, drop, Vec::pop(v))
+//! Call(popped = Vec::pop(v), drop)
//! }
//!
//! drop = {
@@ -273,7 +276,7 @@ define!("mir_return", fn Return() -> BasicBlock);
define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
define!("mir_unreachable", fn Unreachable() -> BasicBlock);
define!("mir_drop", fn Drop<T>(place: T, goto: BasicBlock));
-define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
+define!("mir_call", fn Call(call: (), goto: BasicBlock));
define!("mir_storage_live", fn StorageLive<T>(local: T));
define!("mir_storage_dead", fn StorageDead<T>(local: T));
define!("mir_deinit", fn Deinit<T>(place: T));
@@ -315,6 +318,7 @@ define!(
/// # Examples
///
/// ```rust
+ #[cfg_attr(not(bootstrap), doc = "#![allow(internal_features)]")]
/// #![feature(custom_mir, core_intrinsics)]
///
/// use core::intrinsics::mir::*;
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index d3e454563..eee6e5bcc 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -310,7 +310,7 @@ where
/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
/// this type.
#[derive(Clone, Debug)]
-#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
+#[unstable(feature = "trusted_len", issue = "37572")]
struct FlattenCompat<I, U> {
iter: Fuse<I>,
frontiter: Option<U>,
@@ -464,7 +464,6 @@ where
}
}
-#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
impl<I, U> Iterator for FlattenCompat<I, U>
where
I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -579,7 +578,6 @@ where
}
}
-#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
where
I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -649,7 +647,6 @@ where
}
}
-#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
unsafe impl<const N: usize, I, T> TrustedLen
for FlattenCompat<I, <[T; N] as IntoIterator>::IntoIter>
where
@@ -657,7 +654,6 @@ where
{
}
-#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
unsafe impl<'a, const N: usize, I, T> TrustedLen
for FlattenCompat<I, <&'a [T; N] as IntoIterator>::IntoIter>
where
@@ -665,7 +661,6 @@ where
{
}
-#[cfg_attr(bootstrap, unstable(feature = "trusted_len", issue = "37572"))]
unsafe impl<'a, const N: usize, I, T> TrustedLen
for FlattenCompat<I, <&'a mut [T; N] as IntoIterator>::IntoIter>
where
diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs
new file mode 100644
index 000000000..3c0e80b25
--- /dev/null
+++ b/library/core/src/iter/adapters/map_windows.rs
@@ -0,0 +1,293 @@
+use crate::{
+ fmt,
+ iter::{ExactSizeIterator, FusedIterator},
+ mem::{self, MaybeUninit},
+ ptr,
+};
+
+/// An iterator over the mapped windows of another iterator.
+///
+/// This `struct` is created by the [`Iterator::map_windows`]. See its
+/// documentation for more information.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+pub struct MapWindows<I: Iterator, F, const N: usize> {
+ f: F,
+ inner: MapWindowsInner<I, N>,
+}
+
+struct MapWindowsInner<I: Iterator, const N: usize> {
+ // We fuse the inner iterator because there shouldn't be "holes" in
+ // the sliding window. Once the iterator returns a `None`, we make
+ // our `MapWindows` iterator return `None` forever.
+ iter: Option<I>,
+ // Since iterators are assumed lazy, i.e. it only yields an item when
+ // `Iterator::next()` is called, and `MapWindows` is not an exception.
+ //
+ // Before the first iteration, we keep the buffer `None`. When the user
+ // first call `next` or other methods that makes the iterator advance,
+ // we collect the first `N` items yielded from the inner iterator and
+ // put it into the buffer.
+ //
+ // When the inner iterator has returned a `None` (i.e. fused), we take
+ // away this `buffer` and leave it `None` to reclaim its resources.
+ //
+ // FIXME: should we shrink the size of `buffer` using niche optimization?
+ buffer: Option<Buffer<I::Item, N>>,
+}
+
+// `Buffer` uses two times of space to reduce moves among the iterations.
+// `Buffer<T, N>` is semantically `[MaybeUninit<T>; 2 * N]`. However, due
+// to limitations of const generics, we use this different type. Note that
+// it has the same underlying memory layout.
+struct Buffer<T, const N: usize> {
+ // Invariant: `self.buffer[self.start..self.start + N]` is initialized,
+ // with all other elements being uninitialized. This also
+ // implies that `self.start <= N`.
+ buffer: [[MaybeUninit<T>; N]; 2],
+ start: usize,
+}
+
+impl<I: Iterator, F, const N: usize> MapWindows<I, F, N> {
+ pub(in crate::iter) fn new(iter: I, f: F) -> Self {
+ assert!(N != 0, "array in `Iterator::map_windows` must contain more than 0 elements");
+
+ // Only ZST arrays' length can be so large.
+ if mem::size_of::<I::Item>() == 0 {
+ assert!(
+ N.checked_mul(2).is_some(),
+ "array size of `Iterator::map_windows` is too large"
+ );
+ }
+
+ Self { inner: MapWindowsInner::new(iter), f }
+ }
+}
+
+impl<I: Iterator, const N: usize> MapWindowsInner<I, N> {
+ #[inline]
+ fn new(iter: I) -> Self {
+ Self { iter: Some(iter), buffer: None }
+ }
+
+ fn next_window(&mut self) -> Option<&[I::Item; N]> {
+ let iter = self.iter.as_mut()?;
+ match self.buffer {
+ // It is the first time to advance. We collect
+ // the first `N` items from `self.iter` to initialize `self.buffer`.
+ None => self.buffer = Buffer::try_from_iter(iter),
+ Some(ref mut buffer) => match iter.next() {
+ None => {
+ // Fuse the inner iterator since it yields a `None`.
+ self.iter.take();
+ self.buffer.take();
+ }
+ // Advance the iterator. We first call `next` before changing our buffer
+ // at all. This means that if `next` panics, our invariant is upheld and
+ // our `Drop` impl drops the correct elements.
+ Some(item) => buffer.push(item),
+ },
+ }
+ self.buffer.as_ref().map(Buffer::as_array_ref)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let Some(ref iter) = self.iter else { return (0, Some(0)) };
+ let (lo, hi) = iter.size_hint();
+ if self.buffer.is_some() {
+ // If the first `N` items are already yielded by the inner iterator,
+ // the size hint is then equal to the that of the inner iterator's.
+ (lo, hi)
+ } else {
+ // If the first `N` items are not yet yielded by the inner iterator,
+ // the first `N` elements should be counted as one window, so both bounds
+ // should subtract `N - 1`.
+ (lo.saturating_sub(N - 1), hi.map(|hi| hi.saturating_sub(N - 1)))
+ }
+ }
+}
+
+impl<T, const N: usize> Buffer<T, N> {
+ fn try_from_iter(iter: &mut impl Iterator<Item = T>) -> Option<Self> {
+ let first_half = crate::array::iter_next_chunk(iter).ok()?;
+ let buffer = [MaybeUninit::new(first_half).transpose(), MaybeUninit::uninit_array()];
+ Some(Self { buffer, start: 0 })
+ }
+
+ #[inline]
+ fn buffer_ptr(&self) -> *const MaybeUninit<T> {
+ self.buffer.as_ptr().cast()
+ }
+
+ #[inline]
+ fn buffer_mut_ptr(&mut self) -> *mut MaybeUninit<T> {
+ self.buffer.as_mut_ptr().cast()
+ }
+
+ #[inline]
+ fn as_array_ref(&self) -> &[T; N] {
+ debug_assert!(self.start + N <= 2 * N);
+
+ // SAFETY: our invariant guarantees these elements are initialized.
+ unsafe { &*self.buffer_ptr().add(self.start).cast() }
+ }
+
+ #[inline]
+ fn as_uninit_array_mut(&mut self) -> &mut MaybeUninit<[T; N]> {
+ debug_assert!(self.start + N <= 2 * N);
+
+ // SAFETY: our invariant guarantees these elements are in bounds.
+ unsafe { &mut *self.buffer_mut_ptr().add(self.start).cast() }
+ }
+
+ /// Pushes a new item `next` to the back, and pops the front-most one.
+ ///
+ /// All the elements will be shifted to the front end when pushing reaches
+ /// the back end.
+ fn push(&mut self, next: T) {
+ let buffer_mut_ptr = self.buffer_mut_ptr();
+ debug_assert!(self.start + N <= 2 * N);
+
+ let to_drop = if self.start == N {
+ // We have reached the end of our buffer and have to copy
+ // everything to the start. Example layout for N = 3.
+ //
+ // 0 1 2 3 4 5 0 1 2 3 4 5
+ // ┌───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┐
+ // │ - │ - │ - │ a │ b │ c │ -> │ b │ c │ n │ - │ - │ - │
+ // └───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┘
+ // ↑ ↑
+ // start start
+
+ // SAFETY: the two pointers are valid for reads/writes of N -1
+ // elements because our array's size is semantically 2 * N. The
+ // regions also don't overlap for the same reason.
+ //
+ // We leave the old elements in place. As soon as `start` is set
+ // to 0, we treat them as uninitialized and treat their copies
+ // as initialized.
+ let to_drop = unsafe {
+ ptr::copy_nonoverlapping(buffer_mut_ptr.add(self.start + 1), buffer_mut_ptr, N - 1);
+ (*buffer_mut_ptr.add(N - 1)).write(next);
+ buffer_mut_ptr.add(self.start)
+ };
+ self.start = 0;
+ to_drop
+ } else {
+ // SAFETY: `self.start` is < N as guaranteed by the invariant
+ // plus the check above. Even if the drop at the end panics,
+ // the invariant is upheld.
+ //
+ // Example layout for N = 3:
+ //
+ // 0 1 2 3 4 5 0 1 2 3 4 5
+ // ┌───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┐
+ // │ - │ a │ b │ c │ - │ - │ -> │ - │ - │ b │ c │ n │ - │
+ // └───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┘
+ // ↑ ↑
+ // start start
+ //
+ let to_drop = unsafe {
+ (*buffer_mut_ptr.add(self.start + N)).write(next);
+ buffer_mut_ptr.add(self.start)
+ };
+ self.start += 1;
+ to_drop
+ };
+
+ // SAFETY: the index is valid and this is element `a` in the
+ // diagram above and has not been dropped yet.
+ unsafe { ptr::drop_in_place(to_drop.cast::<T>()) };
+ }
+}
+
+impl<T: Clone, const N: usize> Clone for Buffer<T, N> {
+ fn clone(&self) -> Self {
+ let mut buffer = Buffer {
+ buffer: [MaybeUninit::uninit_array(), MaybeUninit::uninit_array()],
+ start: self.start,
+ };
+ buffer.as_uninit_array_mut().write(self.as_array_ref().clone());
+ buffer
+ }
+}
+
+impl<I, const N: usize> Clone for MapWindowsInner<I, N>
+where
+ I: Iterator + Clone,
+ I::Item: Clone,
+{
+ fn clone(&self) -> Self {
+ Self { iter: self.iter.clone(), buffer: self.buffer.clone() }
+ }
+}
+
+impl<T, const N: usize> Drop for Buffer<T, N> {
+ fn drop(&mut self) {
+ // SAFETY: our invariant guarantees that N elements starting from
+ // `self.start` are initialized. We drop them here.
+ unsafe {
+ let initialized_part: *mut [T] = crate::ptr::slice_from_raw_parts_mut(
+ self.buffer_mut_ptr().add(self.start).cast(),
+ N,
+ );
+ ptr::drop_in_place(initialized_part);
+ }
+ }
+}
+
+#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+impl<I, F, R, const N: usize> Iterator for MapWindows<I, F, N>
+where
+ I: Iterator,
+ F: FnMut(&[I::Item; N]) -> R,
+{
+ type Item = R;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let window = self.inner.next_window()?;
+ let out = (self.f)(window);
+ Some(out)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+// Note that even if the inner iterator not fused, the `MapWindows` is still fused,
+// because we don't allow "holes" in the mapping window.
+#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+impl<I, F, R, const N: usize> FusedIterator for MapWindows<I, F, N>
+where
+ I: Iterator,
+ F: FnMut(&[I::Item; N]) -> R,
+{
+}
+
+#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+impl<I, F, R, const N: usize> ExactSizeIterator for MapWindows<I, F, N>
+where
+ I: ExactSizeIterator,
+ F: FnMut(&[I::Item; N]) -> R,
+{
+}
+
+#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+impl<I: Iterator + fmt::Debug, F, const N: usize> fmt::Debug for MapWindows<I, F, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("MapWindows").field("iter", &self.inner.iter).finish()
+ }
+}
+
+#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+impl<I, F, const N: usize> Clone for MapWindows<I, F, N>
+where
+ I: Iterator + Clone,
+ F: Clone,
+ I::Item: Clone,
+{
+ fn clone(&self) -> Self {
+ Self { f: self.f.clone(), inner: self.inner.clone() }
+ }
+}
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 8cc2b7cec..6f4fa7010 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -16,6 +16,7 @@ mod inspect;
mod intersperse;
mod map;
mod map_while;
+mod map_windows;
mod peekable;
mod rev;
mod scan;
@@ -57,6 +58,9 @@ pub use self::intersperse::{Intersperse, IntersperseWith};
#[stable(feature = "iter_map_while", since = "1.57.0")]
pub use self::map_while::MapWhile;
+#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+pub use self::map_windows::MapWindows;
+
#[unstable(feature = "trusted_random_access", issue = "none")]
pub use self::zip::TrustedRandomAccess;
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index de638552f..ca977d1ef 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -361,6 +361,12 @@ macro_rules! impl_fold_via_try_fold {
(rfold -> try_rfold) => {
impl_fold_via_try_fold! { @internal rfold -> try_rfold }
};
+ (spec_fold -> spec_try_fold) => {
+ impl_fold_via_try_fold! { @internal spec_fold -> spec_try_fold }
+ };
+ (spec_rfold -> spec_try_rfold) => {
+ impl_fold_via_try_fold! { @internal spec_rfold -> spec_try_rfold }
+ };
(@internal $fold:ident -> $try_fold:ident) => {
#[inline]
fn $fold<AAA, FFF>(mut self, init: AAA, fold: FFF) -> AAA
@@ -434,6 +440,8 @@ pub use self::adapters::Copied;
pub use self::adapters::Flatten;
#[stable(feature = "iter_map_while", since = "1.57.0")]
pub use self::adapters::MapWhile;
+#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+pub use self::adapters::MapWindows;
#[unstable(feature = "inplace_iteration", issue = "none")]
pub use self::adapters::SourceIter;
#[stable(feature = "iterator_step_by", since = "1.28.0")]
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 0675e5635..e0ef5071c 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -138,8 +138,6 @@ pub trait FromIterator<A>: Sized {
///
/// # Examples
///
- /// Basic usage:
- ///
/// ```
/// let five_fives = std::iter::repeat(5).take(5);
///
@@ -255,8 +253,6 @@ pub trait IntoIterator {
///
/// # Examples
///
- /// Basic usage:
- ///
/// ```
/// let v = [1, 2, 3];
/// let mut iter = v.into_iter();
@@ -363,8 +359,6 @@ pub trait Extend<A> {
///
/// # Examples
///
- /// Basic usage:
- ///
/// ```
/// // You can extend a String with some chars:
/// let mut message = String::from("abc");
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index 182d9f758..4c8af4eba 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -379,4 +379,66 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
fn nth_back(&mut self, n: usize) -> Option<I::Item> {
(**self).nth_back(n)
}
+ fn rfold<B, F>(self, init: B, f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ self.spec_rfold(init, f)
+ }
+ fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ self.spec_try_rfold(init, f)
+ }
+}
+
+/// Helper trait to specialize `rfold` and `rtry_fold` for `&mut I where I: Sized`
+trait DoubleEndedIteratorRefSpec: DoubleEndedIterator {
+ fn spec_rfold<B, F>(self, init: B, f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B;
+
+ fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>;
+}
+
+impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIteratorRefSpec for &mut I {
+ default fn spec_rfold<B, F>(self, init: B, mut f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let mut accum = init;
+ while let Some(x) = self.next_back() {
+ accum = f(accum, x);
+ }
+ accum
+ }
+
+ default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ let mut accum = init;
+ while let Some(x) = self.next_back() {
+ accum = f(accum, x)?;
+ }
+ try { accum }
+ }
+}
+
+impl<I: DoubleEndedIterator> DoubleEndedIteratorRefSpec for &mut I {
+ impl_fold_via_try_fold! { spec_rfold -> spec_try_rfold }
+
+ fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ (**self).try_rfold(init, f)
+ }
}
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 988352283..ac1fc26a1 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -10,7 +10,8 @@ use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter,
use super::super::{FlatMap, Flatten};
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
use super::super::{
- Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile,
+ Inspect, Map, MapWhile, MapWindows, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take,
+ TakeWhile,
};
fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
@@ -1591,6 +1592,163 @@ pub trait Iterator {
Flatten::new(self)
}
+ /// Calls the given function `f` for each contiguous window of size `N` over
+ /// `self` and returns an iterator over the outputs of `f`. Like [`slice::windows()`],
+ /// the windows during mapping overlap as well.
+ ///
+ /// In the following example, the closure is called three times with the
+ /// arguments `&['a', 'b']`, `&['b', 'c']` and `&['c', 'd']` respectively.
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let strings = "abcd".chars()
+ /// .map_windows(|[x, y]| format!("{}+{}", x, y))
+ /// .collect::<Vec<String>>();
+ ///
+ /// assert_eq!(strings, vec!["a+b", "b+c", "c+d"]);
+ /// ```
+ ///
+ /// Note that the const parameter `N` is usually inferred by the
+ /// destructured argument in the closure.
+ ///
+ /// The returned iterator yields 𝑘 − `N` + 1 items (where 𝑘 is the number of
+ /// items yielded by `self`). If 𝑘 is less than `N`, this method yields an
+ /// empty iterator.
+ ///
+ /// The returned iterator implements [`FusedIterator`], because once `self`
+ /// returns `None`, even if it returns a `Some(T)` again in the next iterations,
+ /// we cannot put it into a contigious array buffer, and thus the returned iterator
+ /// should be fused.
+ ///
+ /// [`slice::windows()`]: slice::windows
+ /// [`FusedIterator`]: crate::iter::FusedIterator
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N` is 0. This check will most probably get changed to a
+ /// compile time error before this method gets stabilized.
+ ///
+ /// ```should_panic
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let iter = std::iter::repeat(0).map_windows(|&[]| ());
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// Building the sums of neighboring numbers.
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let mut it = [1, 3, 8, 1].iter().map_windows(|&[a, b]| a + b);
+ /// assert_eq!(it.next(), Some(4)); // 1 + 3
+ /// assert_eq!(it.next(), Some(11)); // 3 + 8
+ /// assert_eq!(it.next(), Some(9)); // 8 + 1
+ /// assert_eq!(it.next(), None);
+ /// ```
+ ///
+ /// Since the elements in the following example implement `Copy`, we can
+ /// just copy the array and get an iterator over the windows.
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let mut it = "ferris".chars().map_windows(|w: &[_; 3]| *w);
+ /// assert_eq!(it.next(), Some(['f', 'e', 'r']));
+ /// assert_eq!(it.next(), Some(['e', 'r', 'r']));
+ /// assert_eq!(it.next(), Some(['r', 'r', 'i']));
+ /// assert_eq!(it.next(), Some(['r', 'i', 's']));
+ /// assert_eq!(it.next(), None);
+ /// ```
+ ///
+ /// You can also use this function to check the sortedness of an iterator.
+ /// For the simple case, rather use [`Iterator::is_sorted`].
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let mut it = [0.5, 1.0, 3.5, 3.0, 8.5, 8.5, f32::NAN].iter()
+ /// .map_windows(|[a, b]| a <= b);
+ ///
+ /// assert_eq!(it.next(), Some(true)); // 0.5 <= 1.0
+ /// assert_eq!(it.next(), Some(true)); // 1.0 <= 3.5
+ /// assert_eq!(it.next(), Some(false)); // 3.5 <= 3.0
+ /// assert_eq!(it.next(), Some(true)); // 3.0 <= 8.5
+ /// assert_eq!(it.next(), Some(true)); // 8.5 <= 8.5
+ /// assert_eq!(it.next(), Some(false)); // 8.5 <= NAN
+ /// assert_eq!(it.next(), None);
+ /// ```
+ ///
+ /// For non-fused iterators, they are fused after `map_windows`.
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// #[derive(Default)]
+ /// struct NonFusedIterator {
+ /// state: i32,
+ /// }
+ ///
+ /// impl Iterator for NonFusedIterator {
+ /// type Item = i32;
+ ///
+ /// fn next(&mut self) -> Option<i32> {
+ /// let val = self.state;
+ /// self.state = self.state + 1;
+ ///
+ /// // yields `0..5` first, then only even numbers since `6..`.
+ /// if val < 5 || val % 2 == 0 {
+ /// Some(val)
+ /// } else {
+ /// None
+ /// }
+ /// }
+ /// }
+ ///
+ ///
+ /// let mut iter = NonFusedIterator::default();
+ ///
+ /// // yields 0..5 first.
+ /// assert_eq!(iter.next(), Some(0));
+ /// assert_eq!(iter.next(), Some(1));
+ /// assert_eq!(iter.next(), Some(2));
+ /// assert_eq!(iter.next(), Some(3));
+ /// assert_eq!(iter.next(), Some(4));
+ /// // then we can see our iterator going back and forth
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.next(), Some(6));
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.next(), Some(8));
+ /// assert_eq!(iter.next(), None);
+ ///
+ /// // however, with `.map_windows()`, it is fused.
+ /// let mut iter = NonFusedIterator::default()
+ /// .map_windows(|arr: &[_; 2]| *arr);
+ ///
+ /// assert_eq!(iter.next(), Some([0, 1]));
+ /// assert_eq!(iter.next(), Some([1, 2]));
+ /// assert_eq!(iter.next(), Some([2, 3]));
+ /// assert_eq!(iter.next(), Some([3, 4]));
+ /// assert_eq!(iter.next(), None);
+ ///
+ /// // it will always return `None` after the first time.
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.next(), None);
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+ #[rustc_do_not_const_check]
+ fn map_windows<F, R, const N: usize>(self, f: F) -> MapWindows<Self, F, N>
+ where
+ Self: Sized,
+ F: FnMut(&[Self::Item; N]) -> R,
+ {
+ MapWindows::new(self, f)
+ }
+
/// Creates an iterator which ends after the first [`None`].
///
/// After an iterator returns [`None`], future calls may or may not yield
@@ -4018,4 +4176,66 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
fn nth(&mut self, n: usize) -> Option<Self::Item> {
(**self).nth(n)
}
+ fn fold<B, F>(self, init: B, f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ self.spec_fold(init, f)
+ }
+ fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ self.spec_try_fold(init, f)
+ }
+}
+
+/// Helper trait to specialize `fold` and `try_fold` for `&mut I where I: Sized`
+trait IteratorRefSpec: Iterator {
+ fn spec_fold<B, F>(self, init: B, f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B;
+
+ fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>;
+}
+
+impl<I: Iterator + ?Sized> IteratorRefSpec for &mut I {
+ default fn spec_fold<B, F>(self, init: B, mut f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let mut accum = init;
+ while let Some(x) = self.next() {
+ accum = f(accum, x);
+ }
+ accum
+ }
+
+ default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ let mut accum = init;
+ while let Some(x) = self.next() {
+ accum = f(accum, x)?;
+ }
+ try { accum }
+ }
+}
+
+impl<I: Iterator> IteratorRefSpec for &mut I {
+ impl_fold_via_try_fold! { spec_fold -> spec_try_fold }
+
+ fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ (**self).try_fold(init, f)
+ }
}
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 05876f5fc..a2729b374 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -51,7 +51,7 @@
#![cfg(not(test))]
// To run core tests without x.py without ending up with two copies of core, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
-// rustc itself never sets the feature, so this line has no affect there.
+// rustc itself never sets the feature, so this line has no effect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
#![stable(feature = "core", since = "1.6.0")]
#![doc(
@@ -96,6 +96,9 @@
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]
#![warn(multiple_supertrait_upcastable)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+// Do not check link redundancy on bootstraping phase
+#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))]
//
// Library features:
// tidy-alphabetical-start
@@ -165,6 +168,7 @@
#![feature(duration_consts_float)]
#![feature(internal_impls_macro)]
#![feature(ip)]
+#![feature(ip_bits)]
#![feature(is_ascii_octdigit)]
#![feature(maybe_uninit_uninit_array)]
#![feature(ptr_alignment_type)]
@@ -398,7 +402,8 @@ pub mod primitive;
missing_debug_implementations,
dead_code,
unused_imports,
- unsafe_op_in_unsafe_fn
+ unsafe_op_in_unsafe_fn,
+ ambiguous_glob_reexports
)]
#[allow(rustdoc::bare_urls)]
// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
@@ -417,7 +422,7 @@ pub mod arch;
// set up in such a way that directly pulling it here works such that the
// crate uses this crate as its core.
#[path = "../../portable-simd/crates/core_simd/src/mod.rs"]
-#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
+#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn)]
#[allow(rustdoc::bare_urls)]
#[unstable(feature = "portable_simd", issue = "86656")]
mod core_simd;
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 45e5b7627..14cc523b0 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -312,7 +312,6 @@ macro_rules! debug_assert_ne {
/// let c = Ok("abc".to_string());
/// debug_assert_matches!(c, Ok(x) | Err(x) if x.len() < 100);
/// ```
-#[macro_export]
#[unstable(feature = "assert_matches", issue = "82775")]
#[allow_internal_unstable(assert_matches)]
#[rustc_macro_transparency = "semitransparent"]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index e251015dd..5ec751e51 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -140,8 +140,7 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
)]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[rustc_specialization_trait]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
-#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl(implement_via_object = false)]
#[rustc_coinductive]
pub trait Sized {
// Empty.
@@ -174,8 +173,7 @@ pub trait Sized {
/// [nomicon-coerce]: ../../nomicon/coercions.html
#[unstable(feature = "unsize", issue = "18598")]
#[lang = "unsize"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
-#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl(implement_via_object = false)]
pub trait Unsize<T: ?Sized> {
// Empty.
}
@@ -856,8 +854,7 @@ impl<T: ?Sized> StructuralEq for PhantomData<T> {}
reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead"
)]
#[lang = "discriminant_kind"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
-#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl(implement_via_object = false)]
pub trait DiscriminantKind {
/// The type of the discriminant, which must satisfy the trait
/// bounds required by `mem::Discriminant`.
@@ -962,8 +959,7 @@ marker_impls! {
#[unstable(feature = "const_trait_impl", issue = "67792")]
#[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
-#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl(implement_via_object = false)]
#[const_trait]
pub trait Destruct {}
@@ -974,8 +970,7 @@ pub trait Destruct {}
#[unstable(feature = "tuple_trait", issue = "none")]
#[lang = "tuple_trait"]
#[rustc_on_unimplemented(message = "`{Self}` is not a tuple")]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
-#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl(implement_via_object = false)]
pub trait Tuple {}
/// A marker for pointer-like types.
@@ -1020,7 +1015,6 @@ marker_impls! {
// FIXME(adt_const_params): Add to marker_impls call above once not in bootstrap
#[unstable(feature = "adt_const_params", issue = "95174")]
-#[cfg(not(bootstrap))]
impl ConstParamTy for () {}
/// A common trait implemented by all function pointers.
@@ -1030,8 +1024,7 @@ impl ConstParamTy for () {}
reason = "internal trait for implementing various traits for all function pointers"
)]
#[lang = "fn_ptr_trait"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
-#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl(implement_via_object = false)]
pub trait FnPtr: Copy + Clone {
/// Returns the address of the function pointer.
#[lang = "fn_ptr_addr"]
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
index 3805d149b..f5cc86e77 100644
--- a/library/core/src/mem/transmutability.rs
+++ b/library/core/src/mem/transmutability.rs
@@ -7,8 +7,8 @@ use crate::marker::ConstParamTy;
/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
#[unstable(feature = "transmutability", issue = "99571")]
#[lang = "transmute_trait"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
-#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl(implement_via_object = false)]
+#[rustc_coinductive]
pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }>
where
Src: ?Sized,
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index c51913fa8..56460c75e 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -450,6 +450,57 @@ impl Ipv4Addr {
Ipv4Addr { octets: [a, b, c, d] }
}
+ /// The size of an IPv4 address in bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_bits)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// assert_eq!(Ipv4Addr::BITS, 32);
+ /// ```
+ #[unstable(feature = "ip_bits", issue = "113744")]
+ pub const BITS: u32 = 32;
+
+ /// Converts an IPv4 address into host byte order `u32`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_bits)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78);
+ /// assert_eq!(0x12345678, addr.to_bits());
+ /// ```
+ #[rustc_const_unstable(feature = "ip_bits", issue = "113744")]
+ #[unstable(feature = "ip_bits", issue = "113744")]
+ #[must_use]
+ #[inline]
+ pub const fn to_bits(self) -> u32 {
+ u32::from_be_bytes(self.octets)
+ }
+
+ /// Converts a host byte order `u32` into an IPv4 address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_bits)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::from(0x12345678);
+ /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
+ /// ```
+ #[rustc_const_unstable(feature = "ip_bits", issue = "113744")]
+ #[unstable(feature = "ip_bits", issue = "113744")]
+ #[must_use]
+ #[inline]
+ pub const fn from_bits(bits: u32) -> Ipv4Addr {
+ Ipv4Addr { octets: bits.to_be_bytes() }
+ }
+
/// An IPv4 address with the address pointing to localhost: `127.0.0.1`
///
/// # Examples
@@ -1069,37 +1120,19 @@ impl Ord for Ipv4Addr {
#[stable(feature = "ip_u32", since = "1.1.0")]
impl From<Ipv4Addr> for u32 {
- /// Converts an `Ipv4Addr` into a host byte order `u32`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78);
- /// assert_eq!(0x12345678, u32::from(addr));
- /// ```
+ /// Uses [`Ipv4Addr::to_bits`] to convert an IPv4 address to a host byte order `u32`.
#[inline]
fn from(ip: Ipv4Addr) -> u32 {
- u32::from_be_bytes(ip.octets)
+ ip.to_bits()
}
}
#[stable(feature = "ip_u32", since = "1.1.0")]
impl From<u32> for Ipv4Addr {
- /// Converts a host byte order `u32` into an `Ipv4Addr`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv4Addr;
- ///
- /// let addr = Ipv4Addr::from(0x12345678);
- /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
- /// ```
+ /// Uses [`Ipv4Addr::from_bits`] to convert a host byte order `u32` into an IPv4 address.
#[inline]
fn from(ip: u32) -> Ipv4Addr {
- Ipv4Addr { octets: ip.to_be_bytes() }
+ Ipv4Addr::from_bits(ip)
}
}
@@ -1173,6 +1206,65 @@ impl Ipv6Addr {
}
}
+ /// The size of an IPv6 address in bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_bits)]
+ /// use std::net::Ipv6Addr;
+ ///
+ /// assert_eq!(Ipv6Addr::BITS, 128);
+ /// ```
+ #[unstable(feature = "ip_bits", issue = "113744")]
+ pub const BITS: u32 = 128;
+
+ /// Converts an IPv6 address into host byte order `u128`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_bits)]
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::new(
+ /// 0x1020, 0x3040, 0x5060, 0x7080,
+ /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
+ /// );
+ /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
+ /// ```
+ #[rustc_const_unstable(feature = "ip_bits", issue = "113744")]
+ #[unstable(feature = "ip_bits", issue = "113744")]
+ #[must_use]
+ #[inline]
+ pub const fn to_bits(self) -> u128 {
+ u128::from_be_bytes(self.octets)
+ }
+
+ /// Converts a host byte order `u128` into an IPv6 address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_bits)]
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
+ /// assert_eq!(
+ /// Ipv6Addr::new(
+ /// 0x1020, 0x3040, 0x5060, 0x7080,
+ /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
+ /// ),
+ /// addr);
+ /// ```
+ #[rustc_const_unstable(feature = "ip_bits", issue = "113744")]
+ #[unstable(feature = "ip_bits", issue = "113744")]
+ #[must_use]
+ #[inline]
+ pub const fn from_bits(bits: u128) -> Ipv6Addr {
+ Ipv6Addr { octets: bits.to_be_bytes() }
+ }
+
/// An IPv6 address representing localhost: `::1`.
///
/// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other
@@ -1905,44 +1997,18 @@ impl Ord for Ipv6Addr {
#[stable(feature = "i128", since = "1.26.0")]
impl From<Ipv6Addr> for u128 {
- /// Convert an `Ipv6Addr` into a host byte order `u128`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// let addr = Ipv6Addr::new(
- /// 0x1020, 0x3040, 0x5060, 0x7080,
- /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
- /// );
- /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
- /// ```
+ /// Uses [`Ipv6Addr::to_bits`] to convert an IPv6 address to a host byte order `u128`.
#[inline]
fn from(ip: Ipv6Addr) -> u128 {
- u128::from_be_bytes(ip.octets)
+ ip.to_bits()
}
}
#[stable(feature = "i128", since = "1.26.0")]
impl From<u128> for Ipv6Addr {
- /// Convert a host byte order `u128` into an `Ipv6Addr`.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::net::Ipv6Addr;
- ///
- /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
- /// assert_eq!(
- /// Ipv6Addr::new(
- /// 0x1020, 0x3040, 0x5060, 0x7080,
- /// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
- /// ),
- /// addr);
- /// ```
+ /// Uses [`Ipv6Addr::from_bits`] to convert a host byte order `u128` to an IPv6 address.
#[inline]
fn from(ip: u128) -> Ipv6Addr {
- Ipv6Addr::from(ip.to_be_bytes())
+ Ipv6Addr::from_bits(ip)
}
}
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 1199d09b5..1f43520e1 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2126,6 +2126,7 @@ macro_rules! int_impl {
/// assert_eq!(a.rem_euclid(-b), 3);
/// assert_eq!((-a).rem_euclid(-b), 1);
/// ```
+ #[doc(alias = "modulo", alias = "mod")]
#[stable(feature = "euclidean_division", since = "1.38.0")]
#[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")]
#[must_use = "this returns the result of the operation, \
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 6f6b6dbb8..23ca37817 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2024,6 +2024,7 @@ macro_rules! uint_impl {
/// ```
#[doc = concat!("assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type")]
/// ```
+ #[doc(alias = "modulo", alias = "mod")]
#[stable(feature = "euclidean_division", since = "1.38.0")]
#[rustc_const_stable(feature = "const_euclidean_int_methods", since = "1.52.0")]
#[must_use = "this returns the result of the operation, \
@@ -2074,10 +2075,10 @@ macro_rules! uint_impl {
/// Basic usage:
///
/// ```
- /// #![feature(int_roundings)]
#[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")]
/// ```
- #[unstable(feature = "int_roundings", issue = "88581")]
+ #[stable(feature = "int_roundings1", since = "1.73.0")]
+ #[rustc_const_stable(feature = "int_roundings1", since = "1.73.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -2109,11 +2110,11 @@ macro_rules! uint_impl {
/// Basic usage:
///
/// ```
- /// #![feature(int_roundings)]
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")]
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")]
/// ```
- #[unstable(feature = "int_roundings", issue = "88581")]
+ #[stable(feature = "int_roundings1", since = "1.73.0")]
+ #[rustc_const_stable(feature = "int_roundings1", since = "1.73.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
@@ -2134,13 +2135,13 @@ macro_rules! uint_impl {
/// Basic usage:
///
/// ```
- /// #![feature(int_roundings)]
#[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")]
#[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")]
#[doc = concat!("assert_eq!(1_", stringify!($SelfT), ".checked_next_multiple_of(0), None);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_next_multiple_of(2), None);")]
/// ```
- #[unstable(feature = "int_roundings", issue = "88581")]
+ #[stable(feature = "int_roundings1", since = "1.73.0")]
+ #[rustc_const_stable(feature = "int_roundings1", since = "1.73.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 9b6ff76b2..becb63309 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1125,6 +1125,7 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "if you don't need the returned value, use `if let` instead"]
pub fn map_or<U, F>(self, default: U, f: F) -> U
where
F: FnOnce(T) -> U,
@@ -1697,6 +1698,41 @@ impl<T> Option<T> {
mem::replace(self, None)
}
+ /// Takes the value out of the option, but only if the predicate evaluates to
+ /// `true` on a mutable reference to the value.
+ ///
+ /// In other words, replaces `self` with `None` if the predicate returns `true`.
+ /// This method operates similar to [`Option::take`] but conditional.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(option_take_if)]
+ ///
+ /// let mut x = Some(42);
+ ///
+ /// let prev = x.take_if(|v| if *v == 42 {
+ /// *v += 1;
+ /// false
+ /// } else {
+ /// false
+ /// });
+ /// assert_eq!(x, Some(43));
+ /// assert_eq!(prev, None);
+ ///
+ /// let prev = x.take_if(|v| *v == 43);
+ /// assert_eq!(x, None);
+ /// assert_eq!(prev, Some(43));
+ /// ```
+ #[inline]
+ #[unstable(feature = "option_take_if", issue = "98934")]
+ pub fn take_if<P>(&mut self, predicate: P) -> Option<T>
+ where
+ P: FnOnce(&mut T) -> bool,
+ {
+ if self.as_mut().map_or(false, predicate) { self.take() } else { None }
+ }
+
/// Replaces the actual value in the option by the value given in parameter,
/// returning the old value if present,
/// leaving a [`Some`] in its place without deinitializing either one.
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index 5576adde8..c7f04f11e 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -147,16 +147,18 @@ impl<'a> PanicInfo<'a> {
impl fmt::Display for PanicInfo<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("panicked at ")?;
+ self.location.fmt(formatter)?;
if let Some(message) = self.message {
- write!(formatter, "'{}', ", message)?
+ formatter.write_str(":\n")?;
+ formatter.write_fmt(*message)?;
} else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
- write!(formatter, "'{}', ", payload)?
+ formatter.write_str(":\n")?;
+ formatter.write_str(payload)?;
}
// NOTE: we cannot use downcast_ref::<String>() here
// since String is not available in core!
// The payload is a String when `std::panic!` is called with multiple arguments,
// but in that case the message is also available.
-
- self.location.fmt(formatter)
+ Ok(())
}
}
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index f0fcdab00..7b6249207 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -267,16 +267,14 @@ fn assert_failed_inner(
match args {
Some(args) => panic!(
- r#"assertion failed: `(left {} right)`
- left: `{:?}`,
- right: `{:?}`: {}"#,
- op, left, right, args
+ r#"assertion `left {op} right` failed: {args}
+ left: {left:?}
+ right: {right:?}"#
),
None => panic!(
- r#"assertion failed: `(left {} right)`
- left: `{:?}`,
- right: `{:?}`"#,
- op, left, right,
+ r#"assertion `left {op} right` failed
+ left: {left:?}
+ right: {right:?}"#
),
}
}
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 926189a17..ee69d89a4 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1,7 +1,7 @@
use super::*;
use crate::cmp::Ordering::{self, Equal, Greater, Less};
use crate::intrinsics::{self, const_eval_select};
-use crate::mem;
+use crate::mem::{self, SizedTypeProperties};
use crate::slice::{self, SliceIndex};
impl<T: ?Sized> *const T {
@@ -30,6 +30,7 @@ impl<T: ?Sized> *const T {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+ #[rustc_diagnostic_item = "ptr_const_is_null"]
#[inline]
pub const fn is_null(self) -> bool {
#[inline]
@@ -54,6 +55,7 @@ impl<T: ?Sized> *const T {
/// Casts to a pointer of another type.
#[stable(feature = "ptr_cast", since = "1.38.0")]
#[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
+ #[rustc_diagnostic_item = "const_ptr_cast"]
#[inline(always)]
pub const fn cast<U>(self) -> *const U {
self as _
@@ -994,14 +996,23 @@ impl<T: ?Sized> *const T {
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
+ // We could always go back to wrapping if unchecked becomes unacceptable
+ #[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub(self, count: usize) -> Self
where
T: Sized,
{
- // SAFETY: the caller must uphold the safety contract for `offset`.
- unsafe { self.offset((count as isize).wrapping_neg()) }
+ if T::IS_ZST {
+ // Pointer arithmetic does nothing when the pointee is a ZST.
+ self
+ } else {
+ // SAFETY: the caller must uphold the safety contract for `offset`.
+ // Because the pointee is *not* a ZST, that means that `count` is
+ // at most `isize::MAX`, and thus the negation cannot overflow.
+ unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
+ }
}
/// Calculates the offset from a pointer in bytes (convenience for
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index daaa44b1d..040aa0697 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -50,8 +50,7 @@ use crate::hash::{Hash, Hasher};
///
/// [`to_raw_parts`]: *const::to_raw_parts
#[lang = "pointee_trait"]
-#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
-#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
+#[rustc_deny_explicit_impl(implement_via_object = false)]
pub trait Pointee {
/// The type for metadata in pointers and references to `Self`.
#[lang = "metadata_type"]
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index acc9ca29d..5f094ac4e 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -710,6 +710,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
#[inline(always)]
#[must_use]
#[unstable(feature = "ptr_from_ref", issue = "106116")]
+#[rustc_diagnostic_item = "ptr_from_mut"]
pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
r
}
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index c6f438578..9dbb3f9d3 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1,6 +1,7 @@
use super::*;
use crate::cmp::Ordering::{self, Equal, Greater, Less};
use crate::intrinsics::{self, const_eval_select};
+use crate::mem::SizedTypeProperties;
use crate::slice::{self, SliceIndex};
impl<T: ?Sized> *mut T {
@@ -29,6 +30,7 @@ impl<T: ?Sized> *mut T {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
+ #[rustc_diagnostic_item = "ptr_is_null"]
#[inline]
pub const fn is_null(self) -> bool {
#[inline]
@@ -53,6 +55,7 @@ impl<T: ?Sized> *mut T {
/// Casts to a pointer of another type.
#[stable(feature = "ptr_cast", since = "1.38.0")]
#[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
+ #[rustc_diagnostic_item = "ptr_cast"]
#[inline(always)]
pub const fn cast<U>(self) -> *mut U {
self as _
@@ -109,6 +112,7 @@ impl<T: ?Sized> *mut T {
/// [`cast_mut`]: #method.cast_mut
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
+ #[rustc_diagnostic_item = "ptr_cast_const"]
#[inline(always)]
pub const fn cast_const(self) -> *const T {
self as _
@@ -1093,14 +1097,23 @@ impl<T: ?Sized> *mut T {
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
+ // We could always go back to wrapping if unchecked becomes unacceptable
+ #[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
#[inline(always)]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn sub(self, count: usize) -> Self
where
T: Sized,
{
- // SAFETY: the caller must uphold the safety contract for `offset`.
- unsafe { self.offset((count as isize).wrapping_neg()) }
+ if T::IS_ZST {
+ // Pointer arithmetic does nothing when the pointee is a ZST.
+ self
+ } else {
+ // SAFETY: the caller must uphold the safety contract for `offset`.
+ // Because the pointee is *not* a ZST, that means that `count` is
+ // at most `isize::MAX`, and thus the negation cannot overflow.
+ unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
+ }
}
/// Calculates the offset from a pointer in bytes (convenience for
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index b492d2f07..e0fd347a0 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -367,13 +367,14 @@ impl<T: ?Sized> NonNull<T> {
///
/// [the module documentation]: crate::ptr#safety
#[stable(feature = "nonnull", since = "1.25.0")]
- #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
+ #[rustc_const_stable(feature = "const_nonnull_as_ref", since = "1.73.0")]
#[must_use]
#[inline(always)]
pub const unsafe fn as_ref<'a>(&self) -> &'a T {
// SAFETY: the caller must guarantee that `self` meets all the
// requirements for a reference.
- unsafe { &*self.as_ptr() }
+ // `cast_const` avoids a mutable raw pointer deref.
+ unsafe { &*self.as_ptr().cast_const() }
}
/// Returns a unique reference to the value. If the value may be uninitialized, [`as_uninit_mut`]
@@ -462,6 +463,30 @@ impl<T: ?Sized> NonNull<T> {
// And the caller promised the `delta` is sound to add.
unsafe { NonNull { pointer: self.pointer.add(delta) } }
}
+
+ /// See [`pointer::sub`] for semantics and safety requirements.
+ #[inline]
+ pub(crate) const unsafe fn sub(self, delta: usize) -> Self
+ where
+ T: Sized,
+ {
+ // SAFETY: We require that the delta stays in-bounds of the object, and
+ // thus it cannot become null, as no legal objects can be allocated
+ // in such as way that the null address is part of them.
+ // And the caller promised the `delta` is sound to subtract.
+ unsafe { NonNull { pointer: self.pointer.sub(delta) } }
+ }
+
+ /// See [`pointer::sub_ptr`] for semantics and safety requirements.
+ #[inline]
+ pub(crate) const unsafe fn sub_ptr(self, subtrahend: Self) -> usize
+ where
+ T: Sized,
+ {
+ // SAFETY: The caller promised that this is safe to do, and
+ // the non-nullness is irrelevant to the operation.
+ unsafe { self.pointer.sub_ptr(subtrahend.pointer) }
+ }
}
impl<T> NonNull<[T]> {
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index ff7e91d3e..bf8b86677 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -33,7 +33,7 @@ use crate::ptr::NonNull;
#[doc(hidden)]
#[repr(transparent)]
// Lang item used experimentally by Miri to define the semantics of `Unique`.
-#[cfg_attr(not(bootstrap), lang = "ptr_unique")]
+#[lang = "ptr_unique"]
pub struct Unique<T: ?Sized> {
pointer: NonNull<T>,
// NOTE: this marker has no consequences for variance, but is necessary
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 1ee270f4c..6981abc9b 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -749,7 +749,7 @@ impl<T, E> Result<T, E> {
}
/// Returns the provided default (if [`Err`]), or
- /// applies a function to the contained value (if [`Ok`]),
+ /// applies a function to the contained value (if [`Ok`]).
///
/// Arguments passed to `map_or` are eagerly evaluated; if you are passing
/// the result of a function call, it is recommended to use [`map_or_else`],
@@ -768,6 +768,7 @@ impl<T, E> Result<T, E> {
/// ```
#[inline]
#[stable(feature = "result_map_or", since = "1.41.0")]
+ #[must_use = "if you don't need the returned value, use `if let` instead"]
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
match self {
Ok(t) => f(t),
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 7601dd3c7..075347b80 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -1,22 +1,12 @@
//! Comparison traits for `[T]`.
use crate::cmp::{self, BytewiseEq, Ordering};
-use crate::ffi;
+use crate::intrinsics::compare_bytes;
use crate::mem;
use super::from_raw_parts;
use super::memchr;
-extern "C" {
- /// Calls implementation provided memcmp.
- ///
- /// Interprets the data as u8.
- ///
- /// Returns 0 for equal, < 0 for less than and > 0 for greater
- /// than.
- fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> ffi::c_int;
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> PartialEq<[B]> for [A]
where
@@ -74,7 +64,8 @@ where
}
}
-// Use memcmp for bytewise equality when the types allow
+// When each element can be compared byte-wise, we can compare all the bytes
+// from the whole size in one call to the intrinsics.
impl<A, B> SlicePartialEq<B> for [A]
where
A: BytewiseEq<B>,
@@ -88,7 +79,7 @@ where
// The two slices have been checked to have the same size above.
unsafe {
let size = mem::size_of_val(self);
- memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
+ compare_bytes(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
}
}
}
@@ -183,7 +174,7 @@ impl<A: Ord> SliceOrd for A {
}
}
-// memcmp compares a sequence of unsigned bytes lexicographically.
+// `compare_bytes` compares a sequence of unsigned bytes lexicographically.
// this matches the order we want for [u8], but no others (not even [i8]).
impl SliceOrd for u8 {
#[inline]
@@ -195,7 +186,7 @@ impl SliceOrd for u8 {
// SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
// We use the minimum of both lengths which guarantees that both regions are
// valid for reads in that interval.
- let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize };
+ let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
if order == 0 {
order = diff;
}
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index e1e3bcc05..d313e8e01 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -727,7 +727,7 @@ where
}
/// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking
-fn into_range_unchecked(
+pub(crate) fn into_range_unchecked(
len: usize,
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
) -> ops::Range<usize> {
@@ -747,7 +747,7 @@ fn into_range_unchecked(
/// Convert pair of `ops::Bound`s into `ops::Range`.
/// Returns `None` on overflowing indices.
-fn into_range(
+pub(crate) fn into_range(
len: usize,
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
) -> Option<ops::Range<usize>> {
@@ -772,7 +772,7 @@ fn into_range(
/// Convert pair of `ops::Bound`s into `ops::Range`.
/// Panics on overflowing indices.
-fn into_slice_range(
+pub(crate) fn into_slice_range(
len: usize,
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
) -> ops::Range<usize> {
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 5369fe0a9..cc9313553 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -13,7 +13,7 @@ use crate::iter::{
use crate::marker::{PhantomData, Send, Sized, Sync};
use crate::mem::{self, SizedTypeProperties};
use crate::num::NonZeroUsize;
-use crate::ptr::{invalid, invalid_mut, NonNull};
+use crate::ptr::{self, invalid, invalid_mut, NonNull};
use super::{from_raw_parts, from_raw_parts_mut};
@@ -68,7 +68,7 @@ pub struct Iter<'a, T: 'a> {
/// For non-ZSTs, the non-null pointer to the past-the-end element.
///
/// For ZSTs, this is `ptr::invalid(len)`.
- end: *const T,
+ end_or_len: *const T,
_marker: PhantomData<&'a T>,
}
@@ -90,9 +90,9 @@ impl<'a, T> Iter<'a, T> {
let ptr = slice.as_ptr();
// SAFETY: Similar to `IterMut::new`.
unsafe {
- let end = if T::IS_ZST { invalid(slice.len()) } else { ptr.add(slice.len()) };
+ let end_or_len = if T::IS_ZST { invalid(slice.len()) } else { ptr.add(slice.len()) };
- Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData }
+ Self { ptr: NonNull::new_unchecked(ptr as *mut T), end_or_len, _marker: PhantomData }
}
}
@@ -128,7 +128,7 @@ impl<'a, T> Iter<'a, T> {
}
}
-iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
+iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, as_ref, {
fn is_sorted_by<F>(self, mut compare: F) -> bool
where
Self: Sized,
@@ -142,7 +142,7 @@ iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
impl<T> Clone for Iter<'_, T> {
#[inline]
fn clone(&self) -> Self {
- Iter { ptr: self.ptr, end: self.end, _marker: self._marker }
+ Iter { ptr: self.ptr, end_or_len: self.end_or_len, _marker: self._marker }
}
}
@@ -189,7 +189,7 @@ pub struct IterMut<'a, T: 'a> {
/// For non-ZSTs, the non-null pointer to the past-the-end element.
///
/// For ZSTs, this is `ptr::invalid_mut(len)`.
- end: *mut T,
+ end_or_len: *mut T,
_marker: PhantomData<&'a mut T>,
}
@@ -220,15 +220,16 @@ impl<'a, T> IterMut<'a, T> {
// for direct pointer equality with `ptr` to check if the iterator is
// done.
//
- // In the case of a ZST, the end pointer is just the start pointer plus
- // the length, to also allows for the fast `ptr == end` check.
+ // In the case of a ZST, the end pointer is just the length. It's never
+ // used as a pointer at all, and thus it's fine to have no provenance.
//
// See the `next_unchecked!` and `is_empty!` macros as well as the
// `post_inc_start` method for more information.
unsafe {
- let end = if T::IS_ZST { invalid_mut(slice.len()) } else { ptr.add(slice.len()) };
+ let end_or_len =
+ if T::IS_ZST { invalid_mut(slice.len()) } else { ptr.add(slice.len()) };
- Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData }
+ Self { ptr: NonNull::new_unchecked(ptr), end_or_len, _marker: PhantomData }
}
}
@@ -360,7 +361,7 @@ impl<T> AsRef<[T]> for IterMut<'_, T> {
// }
// }
-iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}}
+iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, as_mut, {}}
/// An internal abstraction over the splitting iterators, so that
/// splitn, splitn_mut etc can be implemented once.
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index 96a145e22..95bcd123b 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -1,45 +1,62 @@
//! Macros used by iterators of slice.
-// Shrinks the iterator when T is a ZST, setting the length to `new_len`.
-// `new_len` must not exceed `self.len()`.
-macro_rules! zst_set_len {
- ($self: ident, $new_len: expr) => {{
+/// Convenience & performance macro for consuming the `end_or_len` field, by
+/// giving a `(&mut) usize` or `(&mut) NonNull<T>` depending whether `T` is
+/// or is not a ZST respectively.
+///
+/// Internally, this reads the `end` through a pointer-to-`NonNull` so that
+/// it'll get the appropriate non-null metadata in the backend without needing
+/// to call `assume` manually.
+macro_rules! if_zst {
+ (mut $this:ident, $len:ident => $zst_body:expr, $end:ident => $other_body:expr,) => {{
#![allow(unused_unsafe)] // we're sometimes used within an unsafe block
- // SAFETY: same as `invalid(_mut)`, but the macro doesn't know
- // which versions of that function to call, so open-code it.
- $self.end = unsafe { mem::transmute::<usize, _>($new_len) };
+ if T::IS_ZST {
+ // SAFETY: for ZSTs, the pointer is storing a provenance-free length,
+ // so consuming and updating it as a `usize` is fine.
+ let $len = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::<usize>() };
+ $zst_body
+ } else {
+ // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null
+ let $end = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::<NonNull<T>>() };
+ $other_body
+ }
}};
-}
+ ($this:ident, $len:ident => $zst_body:expr, $end:ident => $other_body:expr,) => {{
+ #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
-// Shrinks the iterator when T is a ZST, reducing the length by `n`.
-// `n` must not exceed `self.len()`.
-macro_rules! zst_shrink {
- ($self: ident, $n: ident) => {
- let new_len = $self.end.addr() - $n;
- zst_set_len!($self, new_len);
- };
+ if T::IS_ZST {
+ let $len = $this.end_or_len.addr();
+ $zst_body
+ } else {
+ // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null
+ let $end = unsafe { *ptr::addr_of!($this.end_or_len).cast::<NonNull<T>>() };
+ $other_body
+ }
+ }};
}
// Inlining is_empty and len makes a huge performance difference
macro_rules! is_empty {
($self: ident) => {
- if T::IS_ZST { $self.end.addr() == 0 } else { $self.ptr.as_ptr() as *const _ == $self.end }
+ if_zst!($self,
+ len => len == 0,
+ end => $self.ptr == end,
+ )
};
}
macro_rules! len {
($self: ident) => {{
- #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
-
- if T::IS_ZST {
- $self.end.addr()
- } else {
- // To get rid of some bounds checks (see `position`), we use ptr_sub instead of
- // offset_from (Tested by `codegen/slice-position-bounds-check`.)
- // SAFETY: by the type invariant pointers are aligned and `start <= end`
- unsafe { $self.end.sub_ptr($self.ptr.as_ptr()) }
- }
+ if_zst!($self,
+ len => len,
+ end => {
+ // To get rid of some bounds checks (see `position`), we use ptr_sub instead of
+ // offset_from (Tested by `codegen/slice-position-bounds-check`.)
+ // SAFETY: by the type invariant pointers are aligned and `start <= end`
+ unsafe { end.sub_ptr($self.ptr) }
+ },
+ )
}};
}
@@ -50,20 +67,21 @@ macro_rules! iterator {
$elem:ty,
$raw_mut:tt,
{$( $mut_:tt )?},
+ $into_ref:ident,
{$($extra:tt)*}
) => {
// Returns the first element and moves the start of the iterator forwards by 1.
// Greatly improves performance compared to an inlined function. The iterator
// must not be empty.
macro_rules! next_unchecked {
- ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
+ ($self: ident) => { $self.post_inc_start(1).$into_ref() }
}
// Returns the last element and moves the end of the iterator backwards by 1.
// Greatly improves performance compared to an inlined function. The iterator
// must not be empty.
macro_rules! next_back_unchecked {
- ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
+ ($self: ident) => { $self.pre_dec_end(1).$into_ref() }
}
impl<'a, T> $name<'a, T> {
@@ -80,33 +98,40 @@ 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: usize) -> * $raw_mut T {
+ unsafe fn post_inc_start(&mut self, offset: usize) -> NonNull<T> {
let old = self.ptr;
- if T::IS_ZST {
- zst_shrink!(self, offset);
- } else {
- // 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 { self.ptr.add(offset) };
+
+ // 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.
+ unsafe {
+ if_zst!(mut self,
+ len => *len = len.unchecked_sub(offset),
+ _end => self.ptr = self.ptr.add(offset),
+ );
}
- old.as_ptr()
+ old
}
// Helper function for moving the end of the iterator backwards by `offset` elements,
// returning the new end.
// Unsafe because the offset must not exceed `self.len()`.
#[inline(always)]
- unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T {
- if T::IS_ZST {
- zst_shrink!(self, offset);
- self.ptr.as_ptr()
- } else {
+ unsafe fn pre_dec_end(&mut self, offset: usize) -> NonNull<T> {
+ if_zst!(mut self,
+ // SAFETY: By our precondition, `offset` can be at most the
+ // current length, so the subtraction can never overflow.
+ len => unsafe {
+ *len = len.unchecked_sub(offset);
+ self.ptr
+ },
// 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.sub(offset) };
- self.end
- }
+ end => unsafe {
+ *end = end.sub(offset);
+ *end
+ },
+ )
}
}
@@ -131,13 +156,9 @@ macro_rules! iterator {
fn next(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
- // SAFETY: `assume` call is safe because slices over non-ZSTs must
- // have a non-null end pointer. The call to `next_unchecked!` is
+ // SAFETY: The call to `next_unchecked!` is
// safe since we check if the iterator is empty first.
unsafe {
- if !<T>::IS_ZST {
- assume(!self.end.is_null());
- }
if is_empty!(self) {
None
} else {
@@ -161,14 +182,10 @@ macro_rules! iterator {
fn nth(&mut self, n: usize) -> Option<$elem> {
if n >= len!(self) {
// This iterator is now empty.
- if T::IS_ZST {
- zst_set_len!(self, 0);
- } else {
- // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
- unsafe {
- self.ptr = NonNull::new_unchecked(self.end as *mut T);
- }
- }
+ if_zst!(mut self,
+ len => *len = 0,
+ end => self.ptr = *end,
+ );
return None;
}
// SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
@@ -375,13 +392,9 @@ macro_rules! iterator {
fn next_back(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
- // SAFETY: `assume` call is safe because slices over non-ZSTs must
- // have a non-null end pointer. The call to `next_back_unchecked!`
+ // SAFETY: The call to `next_back_unchecked!`
// is safe since we check if the iterator is empty first.
unsafe {
- if !<T>::IS_ZST {
- assume(!self.end.is_null());
- }
if is_empty!(self) {
None
} else {
@@ -394,11 +407,10 @@ macro_rules! iterator {
fn nth_back(&mut self, n: usize) -> Option<$elem> {
if n >= len!(self) {
// This iterator is now empty.
- if T::IS_ZST {
- zst_set_len!(self, 0);
- } else {
- self.end = self.ptr.as_ptr();
- }
+ if_zst!(mut self,
+ len => *len = 0,
+ end => *end = self.ptr,
+ );
return None;
}
// SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index e2a2428fb..d95662afd 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -38,7 +38,7 @@ pub mod sort;
mod ascii;
mod cmp;
-mod index;
+pub(crate) mod index;
mod iter;
mod raw;
mod rotate;
@@ -2957,7 +2957,7 @@ impl<T> [T] {
/// elements.
///
/// This sort is unstable (i.e., may reorder equal elements), in-place
- /// (i.e., does not allocate), and *O*(m \* *n* \* log(*n*)) worst-case, where the key function is
+ /// (i.e., does not allocate), and *O*(*m* \* *n* \* log(*n*)) worst-case, where the key function is
/// *O*(*m*).
///
/// # Current implementation
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 772c36055..cd16810c4 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -1439,11 +1439,22 @@ impl<'a> Iterator for EncodeUtf16<'a> {
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let (low, high) = self.chars.size_hint();
- // every char gets either one u16 or two u16,
- // so this iterator is between 1 or 2 times as
- // long as the underlying iterator.
- (low, high.and_then(|n| n.checked_mul(2)))
+ let len = self.chars.iter.len();
+ // The highest bytes:code units ratio occurs for 3-byte sequences,
+ // since a 4-byte sequence results in 2 code units. The lower bound
+ // is therefore determined by assuming the remaining bytes contain as
+ // many 3-byte sequences as possible. The highest bytes:code units
+ // ratio is for 1-byte sequences, so use this for the upper bound.
+ // `(len + 2)` can't overflow, because we know that the `slice::Iter`
+ // belongs to a slice in memory which has a maximum length of
+ // `isize::MAX` (that's well below `usize::MAX`)
+ if self.extra == 0 {
+ ((len + 2) / 3, Some(len))
+ } else {
+ // We're in the middle of a surrogate pair, so add the remaining
+ // surrogate to the bounds.
+ ((len + 2) / 3 + 1, Some(len + 1))
+ }
}
}
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 9a93bb729..e5f34952c 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -267,14 +267,13 @@ impl str {
/// Finds the closest `x` not below `index` where `is_char_boundary(x)` is `true`.
///
+ /// If `index` is greater than the length of the string, this returns the length of the string.
+ ///
/// This method is the natural complement to [`floor_char_boundary`]. See that method
/// for more details.
///
/// [`floor_char_boundary`]: str::floor_char_boundary
///
- /// # Panics
- ///
- /// Panics if `index > self.len()`.
///
/// # Examples
///
@@ -292,7 +291,7 @@ impl str {
#[inline]
pub fn ceil_char_boundary(&self, index: usize) -> usize {
if index > self.len() {
- slice_error_fail(self, index, index)
+ self.len()
} else {
let upper_bound = Ord::min(index + 4, self.len());
self.as_bytes()[index..upper_bound]
@@ -952,6 +951,10 @@ impl str {
///
/// Line terminators are not included in the lines returned by the iterator.
///
+ /// Note that any carriage return (`\r`) not immediately followed by a
+ /// line feed (`\n`) does not split a line. These carriage returns are
+ /// thereby included in the produced lines.
+ ///
/// The final line ending is optional. A string that ends with a final line
/// ending will return the same lines as an otherwise identical string
/// without a final line ending.
@@ -961,18 +964,19 @@ impl str {
/// Basic usage:
///
/// ```
- /// let text = "foo\r\nbar\n\nbaz\n";
+ /// let text = "foo\r\nbar\n\nbaz\r";
/// let mut lines = text.lines();
///
/// assert_eq!(Some("foo"), lines.next());
/// assert_eq!(Some("bar"), lines.next());
/// assert_eq!(Some(""), lines.next());
- /// assert_eq!(Some("baz"), lines.next());
+ /// // Trailing carriage return is included in the last line
+ /// assert_eq!(Some("baz\r"), lines.next());
///
/// assert_eq!(None, lines.next());
/// ```
///
- /// The final line ending isn't required:
+ /// The final line does not require any ending:
///
/// ```
/// let text = "foo\nbar\n\r\nbaz";
@@ -1666,7 +1670,7 @@ impl str {
/// If the pattern allows a reverse search but its results might differ
/// from a forward search, the [`rmatches`] method can be used.
///
- /// [`rmatches`]: str::matches
+ /// [`rmatches`]: str::rmatches
///
/// # Examples
///
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index 91ee2903a..d5d6d60ac 100644
--- a/library/core/src/str/pattern.rs
+++ b/library/core/src/str/pattern.rs
@@ -1750,7 +1750,9 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
1
} else {
// try a few bytes in case first and last byte of the needle are the same
- let Some(second_probe_offset) = (needle.len().saturating_sub(4)..needle.len()).rfind(|&idx| needle[idx] != first_probe) else {
+ let Some(second_probe_offset) =
+ (needle.len().saturating_sub(4)..needle.len()).rfind(|&idx| needle[idx] != first_probe)
+ else {
// fall back to other search methods if we can't find any different bytes
// since we could otherwise hit some degenerate cases
return None;
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 1d52335f2..2b37af66b 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -252,6 +252,58 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
}
}
+/// Implements substring slicing for arbitrary bounds.
+///
+/// Returns a slice of the given string bounded by the byte indices
+/// provided by each bound.
+///
+/// This operation is *O*(1).
+///
+/// # Panics
+///
+/// Panics if `begin` or `end` (if it exists and once adjusted for
+/// inclusion/exclusion) does not point to the starting byte offset of
+/// a character (as defined by `is_char_boundary`), if `begin > end`, or if
+/// `end > len`.
+#[stable(feature = "slice_index_str_with_ops_bound_pair", since = "1.73.0")]
+unsafe impl SliceIndex<str> for (ops::Bound<usize>, ops::Bound<usize>) {
+ type Output = str;
+
+ #[inline]
+ fn get(self, slice: &str) -> Option<&str> {
+ crate::slice::index::into_range(slice.len(), self)?.get(slice)
+ }
+
+ #[inline]
+ fn get_mut(self, slice: &mut str) -> Option<&mut str> {
+ crate::slice::index::into_range(slice.len(), self)?.get_mut(slice)
+ }
+
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const str) -> *const str {
+ let len = (slice as *const [u8]).len();
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+ unsafe { crate::slice::index::into_range_unchecked(len, self).get_unchecked(slice) }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut str {
+ let len = (slice as *mut [u8]).len();
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+ unsafe { crate::slice::index::into_range_unchecked(len, self).get_unchecked_mut(slice) }
+ }
+
+ #[inline]
+ fn index(self, slice: &str) -> &str {
+ crate::slice::index::into_slice_range(slice.len(), self).index(slice)
+ }
+
+ #[inline]
+ fn index_mut(self, slice: &mut str) -> &mut str {
+ crate::slice::index::into_slice_range(slice.len(), self).index_mut(slice)
+ }
+}
+
/// Implements substring slicing with syntax `&self[.. end]` or `&mut
/// self[.. end]`.
///
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 236b7f423..22a1c0978 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -131,6 +131,17 @@ use crate::intrinsics;
use crate::hint::spin_loop;
+// Some architectures don't have byte-sized atomics, which results in LLVM
+// emulating them using a LL/SC loop. However for AtomicBool we can take
+// advantage of the fact that it only ever contains 0 or 1 and use atomic OR/AND
+// instead, which LLVM can emulate using a larger atomic OR/AND operation.
+//
+// This list should only contain architectures which have word-sized atomic-or/
+// atomic-and instructions but don't natively support byte-sized atomics.
+#[cfg(target_has_atomic = "8")]
+const EMULATE_ATOMIC_BOOL: bool =
+ cfg!(any(target_arch = "riscv32", target_arch = "riscv64", target_arch = "loongarch64"));
+
/// A boolean type which can be safely shared between threads.
///
/// This type has the same in-memory representation as a [`bool`].
@@ -553,8 +564,12 @@ impl AtomicBool {
#[cfg(target_has_atomic = "8")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn swap(&self, val: bool, order: Ordering) -> bool {
- // SAFETY: data races are prevented by atomic intrinsics.
- unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
+ if EMULATE_ATOMIC_BOOL {
+ if val { self.fetch_or(true, order) } else { self.fetch_and(false, order) }
+ } else {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
+ }
}
/// Stores a value into the [`bool`] if the current value is the same as the `current` value.
@@ -664,12 +679,39 @@ impl AtomicBool {
success: Ordering,
failure: Ordering,
) -> Result<bool, bool> {
- // SAFETY: data races are prevented by atomic intrinsics.
- match unsafe {
- atomic_compare_exchange(self.v.get(), current as u8, new as u8, success, failure)
- } {
- Ok(x) => Ok(x != 0),
- Err(x) => Err(x != 0),
+ if EMULATE_ATOMIC_BOOL {
+ // Pick the strongest ordering from success and failure.
+ let order = match (success, failure) {
+ (SeqCst, _) => SeqCst,
+ (_, SeqCst) => SeqCst,
+ (AcqRel, _) => AcqRel,
+ (_, AcqRel) => {
+ panic!("there is no such thing as an acquire-release failure ordering")
+ }
+ (Release, Acquire) => AcqRel,
+ (Acquire, _) => Acquire,
+ (_, Acquire) => Acquire,
+ (Release, Relaxed) => Release,
+ (_, Release) => panic!("there is no such thing as a release failure ordering"),
+ (Relaxed, Relaxed) => Relaxed,
+ };
+ let old = if current == new {
+ // This is a no-op, but we still need to perform the operation
+ // for memory ordering reasons.
+ self.fetch_or(false, order)
+ } else {
+ // This sets the value to the new one and returns the old one.
+ self.swap(new, order)
+ };
+ if old == current { Ok(old) } else { Err(old) }
+ } else {
+ // SAFETY: data races are prevented by atomic intrinsics.
+ match unsafe {
+ atomic_compare_exchange(self.v.get(), current as u8, new as u8, success, failure)
+ } {
+ Ok(x) => Ok(x != 0),
+ Err(x) => Err(x != 0),
+ }
}
}
@@ -719,6 +761,10 @@ impl AtomicBool {
success: Ordering,
failure: Ordering,
) -> Result<bool, bool> {
+ if EMULATE_ATOMIC_BOOL {
+ return self.compare_exchange(current, new, success, failure);
+ }
+
// SAFETY: data races are prevented by atomic intrinsics.
match unsafe {
atomic_compare_exchange_weak(self.v.get(), current as u8, new as u8, success, failure)
@@ -1958,14 +2004,12 @@ macro_rules! atomic_int {
$stable_from:meta,
$stable_nand:meta,
$const_stable:meta,
- $stable_init_const:meta,
$diagnostic_item:meta,
$s_int_type:literal,
$extra_feature:expr,
$min_fn:ident, $max_fn:ident,
$align:expr,
- $atomic_new:expr,
- $int_type:ident $atomic_type:ident $atomic_init:ident) => {
+ $int_type:ident $atomic_type:ident) => {
/// An integer type which can be safely shared between threads.
///
/// This type has the same in-memory representation as the underlying
@@ -1988,15 +2032,6 @@ macro_rules! atomic_int {
v: UnsafeCell<$int_type>,
}
- /// An atomic integer initialized to `0`.
- #[$stable_init_const]
- #[deprecated(
- since = "1.34.0",
- note = "the `new` function is now preferred",
- suggestion = $atomic_new,
- )]
- pub const $atomic_init: $atomic_type = $atomic_type::new(0);
-
#[$stable]
impl Default for $atomic_type {
#[inline]
@@ -2874,14 +2909,12 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"),
"i8",
"",
atomic_min, atomic_max,
1,
- "AtomicI8::new(0)",
- i8 AtomicI8 ATOMIC_I8_INIT
+ i8 AtomicI8
}
#[cfg(target_has_atomic_load_store = "8")]
atomic_int! {
@@ -2894,14 +2927,12 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"),
"u8",
"",
atomic_umin, atomic_umax,
1,
- "AtomicU8::new(0)",
- u8 AtomicU8 ATOMIC_U8_INIT
+ u8 AtomicU8
}
#[cfg(target_has_atomic_load_store = "16")]
atomic_int! {
@@ -2914,14 +2945,12 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"),
"i16",
"",
atomic_min, atomic_max,
2,
- "AtomicI16::new(0)",
- i16 AtomicI16 ATOMIC_I16_INIT
+ i16 AtomicI16
}
#[cfg(target_has_atomic_load_store = "16")]
atomic_int! {
@@ -2934,14 +2963,12 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"),
"u16",
"",
atomic_umin, atomic_umax,
2,
- "AtomicU16::new(0)",
- u16 AtomicU16 ATOMIC_U16_INIT
+ u16 AtomicU16
}
#[cfg(target_has_atomic_load_store = "32")]
atomic_int! {
@@ -2954,14 +2981,12 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"),
"i32",
"",
atomic_min, atomic_max,
4,
- "AtomicI32::new(0)",
- i32 AtomicI32 ATOMIC_I32_INIT
+ i32 AtomicI32
}
#[cfg(target_has_atomic_load_store = "32")]
atomic_int! {
@@ -2974,14 +2999,12 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"),
"u32",
"",
atomic_umin, atomic_umax,
4,
- "AtomicU32::new(0)",
- u32 AtomicU32 ATOMIC_U32_INIT
+ u32 AtomicU32
}
#[cfg(target_has_atomic_load_store = "64")]
atomic_int! {
@@ -2994,14 +3017,12 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"),
"i64",
"",
atomic_min, atomic_max,
8,
- "AtomicI64::new(0)",
- i64 AtomicI64 ATOMIC_I64_INIT
+ i64 AtomicI64
}
#[cfg(target_has_atomic_load_store = "64")]
atomic_int! {
@@ -3014,14 +3035,12 @@ atomic_int! {
stable(feature = "integer_atomics_stable", since = "1.34.0"),
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"),
"u64",
"",
atomic_umin, atomic_umax,
8,
- "AtomicU64::new(0)",
- u64 AtomicU64 ATOMIC_U64_INIT
+ u64 AtomicU64
}
#[cfg(target_has_atomic_load_store = "128")]
atomic_int! {
@@ -3034,14 +3053,12 @@ atomic_int! {
unstable(feature = "integer_atomics", issue = "99069"),
unstable(feature = "integer_atomics", issue = "99069"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
"i128",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
16,
- "AtomicI128::new(0)",
- i128 AtomicI128 ATOMIC_I128_INIT
+ i128 AtomicI128
}
#[cfg(target_has_atomic_load_store = "128")]
atomic_int! {
@@ -3054,19 +3071,17 @@ atomic_int! {
unstable(feature = "integer_atomics", issue = "99069"),
unstable(feature = "integer_atomics", issue = "99069"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
- unstable(feature = "integer_atomics", issue = "99069"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
"u128",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
16,
- "AtomicU128::new(0)",
- u128 AtomicU128 ATOMIC_U128_INIT
+ u128 AtomicU128
}
+#[cfg(target_has_atomic_load_store = "ptr")]
macro_rules! atomic_int_ptr_sized {
( $($target_pointer_width:literal $align:literal)* ) => { $(
- #[cfg(target_has_atomic_load_store = "ptr")]
#[cfg(target_pointer_width = $target_pointer_width)]
atomic_int! {
cfg(target_has_atomic = "ptr"),
@@ -3078,16 +3093,13 @@ macro_rules! atomic_int_ptr_sized {
stable(feature = "atomic_from", since = "1.23.0"),
stable(feature = "atomic_nand", since = "1.27.0"),
rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
- stable(feature = "rust1", since = "1.0.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"),
"isize",
"",
atomic_min, atomic_max,
$align,
- "AtomicIsize::new(0)",
- isize AtomicIsize ATOMIC_ISIZE_INIT
+ isize AtomicIsize
}
- #[cfg(target_has_atomic_load_store = "ptr")]
#[cfg(target_pointer_width = $target_pointer_width)]
atomic_int! {
cfg(target_has_atomic = "ptr"),
@@ -3099,18 +3111,37 @@ macro_rules! atomic_int_ptr_sized {
stable(feature = "atomic_from", since = "1.23.0"),
stable(feature = "atomic_nand", since = "1.27.0"),
rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
- stable(feature = "rust1", since = "1.0.0"),
cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"),
"usize",
"",
atomic_umin, atomic_umax,
$align,
- "AtomicUsize::new(0)",
- usize AtomicUsize ATOMIC_USIZE_INIT
+ usize AtomicUsize
}
+
+ /// An [`AtomicIsize`] initialized to `0`.
+ #[cfg(target_pointer_width = $target_pointer_width)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[deprecated(
+ since = "1.34.0",
+ note = "the `new` function is now preferred",
+ suggestion = "AtomicIsize::new(0)",
+ )]
+ pub const ATOMIC_ISIZE_INIT: AtomicIsize = AtomicIsize::new(0);
+
+ /// An [`AtomicUsize`] initialized to `0`.
+ #[cfg(target_pointer_width = $target_pointer_width)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[deprecated(
+ since = "1.34.0",
+ note = "the `new` function is now preferred",
+ suggestion = "AtomicUsize::new(0)",
+ )]
+ pub const ATOMIC_USIZE_INIT: AtomicUsize = AtomicUsize::new(0);
)* };
}
+#[cfg(target_has_atomic_load_store = "ptr")]
atomic_int_ptr_sized! {
"16" 2
"32" 4
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index ac8d04a82..7782ace69 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -1,7 +1,6 @@
// See src/libstd/primitive_docs.rs for documentation.
use crate::cmp::Ordering::{self, *};
-#[cfg(not(bootstrap))]
use crate::marker::ConstParamTy;
use crate::marker::{StructuralEq, StructuralPartialEq};
@@ -51,7 +50,6 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[unstable(feature = "structural_match", issue = "31434")]
- #[cfg(not(bootstrap))]
impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+)
{}
}
diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs
index a8f6b7ebb..8d2d31b64 100644
--- a/library/core/tests/any.rs
+++ b/library/core/tests/any.rs
@@ -147,65 +147,3 @@ fn dyn_type_name() {
std::any::type_name::<dyn Foo<Bar = i32> + Send + Sync>()
);
}
-
-// Test the `Provider` API.
-
-struct SomeConcreteType {
- some_string: String,
-}
-
-impl Provider for SomeConcreteType {
- fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
- demand
- .provide_ref::<String>(&self.some_string)
- .provide_ref::<str>(&self.some_string)
- .provide_value_with::<String>(|| "bye".to_owned());
- }
-}
-
-// Test the provide and request mechanisms with a by-reference trait object.
-#[test]
-fn test_provider() {
- let obj: &dyn Provider = &SomeConcreteType { some_string: "hello".to_owned() };
-
- assert_eq!(&**request_ref::<String>(obj).unwrap(), "hello");
- assert_eq!(&*request_value::<String>(obj).unwrap(), "bye");
- assert_eq!(request_value::<u8>(obj), None);
-}
-
-// Test the provide and request mechanisms with a boxed trait object.
-#[test]
-fn test_provider_boxed() {
- let obj: Box<dyn Provider> = Box::new(SomeConcreteType { some_string: "hello".to_owned() });
-
- assert_eq!(&**request_ref::<String>(&*obj).unwrap(), "hello");
- assert_eq!(&*request_value::<String>(&*obj).unwrap(), "bye");
- assert_eq!(request_value::<u8>(&*obj), None);
-}
-
-// Test the provide and request mechanisms with a concrete object.
-#[test]
-fn test_provider_concrete() {
- let obj = SomeConcreteType { some_string: "hello".to_owned() };
-
- assert_eq!(&**request_ref::<String>(&obj).unwrap(), "hello");
- assert_eq!(&*request_value::<String>(&obj).unwrap(), "bye");
- assert_eq!(request_value::<u8>(&obj), None);
-}
-
-trait OtherTrait: Provider {}
-
-impl OtherTrait for SomeConcreteType {}
-
-impl dyn OtherTrait {
- fn get_ref<T: 'static + ?Sized>(&self) -> Option<&T> {
- request_ref::<T>(self)
- }
-}
-
-// Test the provide and request mechanisms via an intermediate trait.
-#[test]
-fn test_provider_intermediate() {
- let obj: &dyn OtherTrait = &SomeConcreteType { some_string: "hello".to_owned() };
- assert_eq!(obj.get_ref::<str>().unwrap(), "hello");
-}
diff --git a/library/core/tests/error.rs b/library/core/tests/error.rs
new file mode 100644
index 000000000..cb7cb5441
--- /dev/null
+++ b/library/core/tests/error.rs
@@ -0,0 +1,66 @@
+use core::error::{request_value, request_ref, Request};
+
+// Test the `Request` API.
+#[derive(Debug)]
+struct SomeConcreteType {
+ some_string: String,
+}
+
+impl std::fmt::Display for SomeConcreteType {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "A")
+ }
+}
+
+impl std::error::Error for SomeConcreteType {
+ fn provide<'a>(&'a self, request: &mut Request<'a>) {
+ request
+ .provide_ref::<String>(&self.some_string)
+ .provide_ref::<str>(&self.some_string)
+ .provide_value_with::<String>(|| "bye".to_owned());
+ }
+}
+
+// Test the Error.provide and request mechanisms with a by-reference trait object.
+#[test]
+fn test_error_generic_member_access() {
+ let obj = &SomeConcreteType { some_string: "hello".to_owned() };
+
+ assert_eq!(request_ref::<String>(&*obj).unwrap(), "hello");
+ assert_eq!(request_value::<String>(&*obj).unwrap(), "bye");
+ assert_eq!(request_value::<u8>(&obj), None);
+}
+
+// Test the Error.provide and request mechanisms with a by-reference trait object.
+#[test]
+fn test_request_constructor() {
+ let obj: &dyn std::error::Error = &SomeConcreteType { some_string: "hello".to_owned() };
+
+ assert_eq!(request_ref::<String>(&*obj).unwrap(), "hello");
+ assert_eq!(request_value::<String>(&*obj).unwrap(), "bye");
+ assert_eq!(request_value::<u8>(&obj), None);
+}
+
+// Test the Error.provide and request mechanisms with a boxed trait object.
+#[test]
+fn test_error_generic_member_access_boxed() {
+ let obj: Box<dyn std::error::Error> =
+ Box::new(SomeConcreteType { some_string: "hello".to_owned() });
+
+ assert_eq!(request_ref::<String>(&*obj).unwrap(), "hello");
+ assert_eq!(request_value::<String>(&*obj).unwrap(), "bye");
+
+ // NOTE: Box<E> only implements Error when E: Error + Sized, which means we can't pass a
+ // Box<dyn Error> to request_value.
+ //assert_eq!(request_value::<String>(&obj).unwrap(), "bye");
+}
+
+// Test the Error.provide and request mechanisms with a concrete object.
+#[test]
+fn test_error_generic_member_access_concrete() {
+ let obj = SomeConcreteType { some_string: "hello".to_owned() };
+
+ assert_eq!(request_ref::<String>(&obj).unwrap(), "hello");
+ assert_eq!(request_value::<String>(&obj).unwrap(), "bye");
+ assert_eq!(request_value::<u8>(&obj), None);
+}
diff --git a/library/core/tests/iter/adapters/map_windows.rs b/library/core/tests/iter/adapters/map_windows.rs
new file mode 100644
index 000000000..7fb2408f8
--- /dev/null
+++ b/library/core/tests/iter/adapters/map_windows.rs
@@ -0,0 +1,283 @@
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+
+#[cfg(not(panic = "abort"))]
+mod drop_checks {
+ //! These tests mainly make sure the elements are correctly dropped.
+ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst};
+
+ #[derive(Debug)]
+ struct DropInfo {
+ dropped_twice: AtomicBool,
+ alive_count: AtomicUsize,
+ }
+
+ impl DropInfo {
+ const fn new() -> Self {
+ Self { dropped_twice: AtomicBool::new(false), alive_count: AtomicUsize::new(0) }
+ }
+
+ #[track_caller]
+ fn check(&self) {
+ assert!(!self.dropped_twice.load(SeqCst), "a value was dropped twice");
+ assert_eq!(self.alive_count.load(SeqCst), 0);
+ }
+ }
+
+ #[derive(Debug)]
+ struct DropCheck<'a> {
+ info: &'a DropInfo,
+ was_dropped: bool,
+ }
+
+ impl<'a> DropCheck<'a> {
+ fn new(info: &'a DropInfo) -> Self {
+ info.alive_count.fetch_add(1, SeqCst);
+
+ Self { info, was_dropped: false }
+ }
+ }
+
+ impl Drop for DropCheck<'_> {
+ fn drop(&mut self) {
+ if self.was_dropped {
+ self.info.dropped_twice.store(true, SeqCst);
+ }
+ self.was_dropped = true;
+
+ self.info.alive_count.fetch_sub(1, SeqCst);
+ }
+ }
+
+ fn iter(info: &DropInfo, len: usize, panic_at: usize) -> impl Iterator<Item = DropCheck<'_>> {
+ (0..len).map(move |i| {
+ if i == panic_at {
+ panic!("intended panic");
+ }
+ DropCheck::new(info)
+ })
+ }
+
+ #[track_caller]
+ fn check<const N: usize>(len: usize, panic_at: usize) {
+ check_drops(|info| {
+ iter(info, len, panic_at).map_windows(|_: &[_; N]| {}).last();
+ });
+ }
+
+ #[track_caller]
+ fn check_drops(f: impl FnOnce(&DropInfo)) {
+ let info = DropInfo::new();
+ let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
+ f(&info);
+ }));
+ info.check();
+ }
+
+ #[test]
+ fn no_iter_panic_n1() {
+ check::<1>(0, 100);
+ check::<1>(1, 100);
+ check::<1>(2, 100);
+ check::<1>(13, 100);
+ }
+
+ #[test]
+ fn no_iter_panic_n2() {
+ check::<2>(0, 100);
+ check::<2>(1, 100);
+ check::<2>(2, 100);
+ check::<2>(3, 100);
+ check::<2>(13, 100);
+ }
+
+ #[test]
+ fn no_iter_panic_n5() {
+ check::<5>(0, 100);
+ check::<5>(1, 100);
+ check::<5>(2, 100);
+ check::<5>(13, 100);
+ check::<5>(30, 100);
+ }
+
+ #[test]
+ fn panic_in_first_batch() {
+ check::<1>(7, 0);
+
+ check::<2>(7, 0);
+ check::<2>(7, 1);
+
+ check::<3>(7, 0);
+ check::<3>(7, 1);
+ check::<3>(7, 2);
+ }
+
+ #[test]
+ fn panic_in_middle() {
+ check::<1>(7, 1);
+ check::<1>(7, 5);
+ check::<1>(7, 6);
+
+ check::<2>(7, 2);
+ check::<2>(7, 5);
+ check::<2>(7, 6);
+
+ check::<5>(13, 5);
+ check::<5>(13, 8);
+ check::<5>(13, 12);
+ }
+
+ #[test]
+ fn len_equals_n() {
+ check::<1>(1, 100);
+ check::<1>(1, 0);
+
+ check::<2>(2, 100);
+ check::<2>(2, 0);
+ check::<2>(2, 1);
+
+ check::<5>(5, 100);
+ check::<5>(5, 0);
+ check::<5>(5, 1);
+ check::<5>(5, 4);
+ }
+}
+
+#[test]
+fn output_n1() {
+ assert_eq!("".chars().map_windows(|[c]| *c).collect::<Vec<_>>(), vec![]);
+ assert_eq!("x".chars().map_windows(|[c]| *c).collect::<Vec<_>>(), vec!['x']);
+ assert_eq!("abcd".chars().map_windows(|[c]| *c).collect::<Vec<_>>(), vec!['a', 'b', 'c', 'd']);
+}
+
+#[test]
+fn output_n2() {
+ assert_eq!(
+ "".chars().map_windows(|a: &[_; 2]| *a).collect::<Vec<_>>(),
+ <Vec<[char; 2]>>::new(),
+ );
+ assert_eq!("ab".chars().map_windows(|a: &[_; 2]| *a).collect::<Vec<_>>(), vec![['a', 'b']]);
+ assert_eq!(
+ "abcd".chars().map_windows(|a: &[_; 2]| *a).collect::<Vec<_>>(),
+ vec![['a', 'b'], ['b', 'c'], ['c', 'd']],
+ );
+}
+
+#[test]
+fn test_case_from_pr_82413_comment() {
+ for () in std::iter::repeat("0".to_owned()).map_windows(|_: &[_; 3]| {}).take(4) {}
+}
+
+#[test]
+#[should_panic = "array in `Iterator::map_windows` must contain more than 0 elements"]
+fn check_zero_window() {
+ let _ = std::iter::repeat(0).map_windows(|_: &[_; 0]| ());
+}
+
+#[test]
+fn test_zero_sized_type() {
+ #[derive(Copy, Clone, Debug, Eq, PartialEq)]
+ struct Data;
+ let data: Vec<_> =
+ std::iter::repeat(Data).take(10).map_windows(|arr: &[Data; 5]| *arr).collect();
+ assert_eq!(data, [[Data; 5]; 6]);
+}
+
+#[test]
+#[should_panic = "array size of `Iterator::map_windows` is too large"]
+fn test_too_large_array_size() {
+ let _ = std::iter::repeat(()).map_windows(|arr: &[(); usize::MAX]| *arr);
+}
+
+#[test]
+fn test_laziness() {
+ let counter = AtomicUsize::new(0);
+ let mut iter = (0..5)
+ .inspect(|_| {
+ counter.fetch_add(1, SeqCst);
+ })
+ .map_windows(|arr: &[i32; 2]| *arr);
+ assert_eq!(counter.load(SeqCst), 0);
+
+ assert_eq!(iter.next(), Some([0, 1]));
+ // The first iteration consumes N items (N = 2).
+ assert_eq!(counter.load(SeqCst), 2);
+
+ assert_eq!(iter.next(), Some([1, 2]));
+ assert_eq!(counter.load(SeqCst), 3);
+
+ assert_eq!(iter.next(), Some([2, 3]));
+ assert_eq!(counter.load(SeqCst), 4);
+
+ assert_eq!(iter.next(), Some([3, 4]));
+ assert_eq!(counter.load(SeqCst), 5);
+
+ assert_eq!(iter.next(), None);
+ assert_eq!(counter.load(SeqCst), 5);
+}
+
+#[test]
+fn test_size_hint() {
+ struct SizeHintCheckHelper((usize, Option<usize>));
+
+ impl Iterator for SizeHintCheckHelper {
+ type Item = i32;
+
+ fn next(&mut self) -> Option<i32> {
+ let (ref mut lo, ref mut hi) = self.0;
+ let next = (*hi != Some(0)).then_some(0);
+ *lo = lo.saturating_sub(1);
+ if let Some(hi) = hi {
+ *hi = hi.saturating_sub(1);
+ }
+ next
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0
+ }
+ }
+
+ fn check_size_hint<const N: usize>(
+ size_hint: (usize, Option<usize>),
+ mut mapped_size_hint: (usize, Option<usize>),
+ ) {
+ let mut iter = SizeHintCheckHelper(size_hint);
+ let mut mapped_iter = iter.by_ref().map_windows(|_: &[_; N]| ());
+ while mapped_iter.size_hint().0 > 0 {
+ assert_eq!(mapped_iter.size_hint(), mapped_size_hint);
+ assert!(mapped_iter.next().is_some());
+ mapped_size_hint.0 -= 1;
+ mapped_size_hint.1 = mapped_size_hint.1.map(|hi| hi.saturating_sub(1));
+ }
+ }
+
+ check_size_hint::<1>((0, None), (0, None));
+ check_size_hint::<1>((0, Some(0)), (0, Some(0)));
+ check_size_hint::<1>((0, Some(2)), (0, Some(2)));
+ check_size_hint::<1>((1, None), (1, None));
+ check_size_hint::<1>((1, Some(1)), (1, Some(1)));
+ check_size_hint::<1>((1, Some(4)), (1, Some(4)));
+ check_size_hint::<1>((5, None), (5, None));
+ check_size_hint::<1>((5, Some(5)), (5, Some(5)));
+ check_size_hint::<1>((5, Some(10)), (5, Some(10)));
+
+ check_size_hint::<2>((0, None), (0, None));
+ check_size_hint::<2>((0, Some(0)), (0, Some(0)));
+ check_size_hint::<2>((0, Some(2)), (0, Some(1)));
+ check_size_hint::<2>((1, None), (0, None));
+ check_size_hint::<2>((1, Some(1)), (0, Some(0)));
+ check_size_hint::<2>((1, Some(4)), (0, Some(3)));
+ check_size_hint::<2>((5, None), (4, None));
+ check_size_hint::<2>((5, Some(5)), (4, Some(4)));
+ check_size_hint::<2>((5, Some(10)), (4, Some(9)));
+
+ check_size_hint::<5>((0, None), (0, None));
+ check_size_hint::<5>((0, Some(0)), (0, Some(0)));
+ check_size_hint::<5>((0, Some(2)), (0, Some(0)));
+ check_size_hint::<5>((1, None), (0, None));
+ check_size_hint::<5>((1, Some(1)), (0, Some(0)));
+ check_size_hint::<5>((1, Some(4)), (0, Some(0)));
+ check_size_hint::<5>((5, None), (1, None));
+ check_size_hint::<5>((5, Some(5)), (1, Some(1)));
+ check_size_hint::<5>((5, Some(10)), (1, Some(6)));
+}
diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs
index ca3463aa7..dedb4c0a9 100644
--- a/library/core/tests/iter/adapters/mod.rs
+++ b/library/core/tests/iter/adapters/mod.rs
@@ -13,6 +13,7 @@ mod fuse;
mod inspect;
mod intersperse;
mod map;
+mod map_windows;
mod peekable;
mod scan;
mod skip;
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index 9eebfb1f1..995bbf0e2 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -1,3 +1,4 @@
+use core::cmp::Ordering;
use core::num::NonZeroUsize;
/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped
@@ -371,11 +372,39 @@ fn test_by_ref() {
#[test]
fn test_is_sorted() {
+ // Tests on integers
assert!([1, 2, 2, 9].iter().is_sorted());
assert!(![1, 3, 2].iter().is_sorted());
assert!([0].iter().is_sorted());
- assert!(std::iter::empty::<i32>().is_sorted());
+ assert!([0, 0].iter().is_sorted());
+ assert!(core::iter::empty::<i32>().is_sorted());
+
+ // Tests on floats
+ assert!([1.0f32, 2.0, 2.0, 9.0].iter().is_sorted());
+ assert!(![1.0f32, 3.0f32, 2.0f32].iter().is_sorted());
+ assert!([0.0f32].iter().is_sorted());
+ assert!([0.0f32, 0.0f32].iter().is_sorted());
+ // Test cases with NaNs
+ assert!([f32::NAN].iter().is_sorted());
+ assert!(![f32::NAN, f32::NAN].iter().is_sorted());
assert!(![0.0, 1.0, f32::NAN].iter().is_sorted());
+ // Tests from <https://github.com/rust-lang/rust/pull/55045#discussion_r229689884>
+ assert!(![f32::NAN, f32::NAN, f32::NAN].iter().is_sorted());
+ assert!(![1.0, f32::NAN, 2.0].iter().is_sorted());
+ assert!(![2.0, f32::NAN, 1.0].iter().is_sorted());
+ assert!(![2.0, f32::NAN, 1.0, 7.0].iter().is_sorted());
+ assert!(![2.0, f32::NAN, 1.0, 0.0].iter().is_sorted());
+ assert!(![-f32::NAN, -1.0, 0.0, 1.0, f32::NAN].iter().is_sorted());
+ assert!(![f32::NAN, -f32::NAN, -1.0, 0.0, 1.0].iter().is_sorted());
+ assert!(![1.0, f32::NAN, -f32::NAN, -1.0, 0.0].iter().is_sorted());
+ assert!(![0.0, 1.0, f32::NAN, -f32::NAN, -1.0].iter().is_sorted());
+ assert!(![-1.0, 0.0, 1.0, f32::NAN, -f32::NAN].iter().is_sorted());
+
+ // Tests for is_sorted_by
+ assert!(![6, 2, 8, 5, 1, -60, 1337].iter().is_sorted());
+ assert!([6, 2, 8, 5, 1, -60, 1337].iter().is_sorted_by(|_, _| Some(Ordering::Less)));
+
+ // Tests for is_sorted_by_key
assert!([-2, -1, 0, 3].iter().is_sorted());
assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
assert!(!["c", "bb", "aaa"].iter().is_sorted());
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 3e6d31fcd..7a6def37a 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -93,7 +93,7 @@
#![feature(const_option)]
#![feature(const_option_ext)]
#![feature(const_result)]
-#![feature(integer_atomics)]
+#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![feature(int_roundings)]
#![feature(slice_group_by)]
#![feature(split_array)]
@@ -105,11 +105,14 @@
#![feature(const_slice_from_ref)]
#![feature(waker_getters)]
#![feature(slice_flatten)]
-#![feature(provide_any)]
+#![feature(error_generic_member_access)]
+#![feature(error_in_core)]
+#![feature(trait_upcasting)]
#![feature(utf8_chunks)]
#![feature(is_ascii_octdigit)]
#![feature(get_many_mut)]
#![feature(offset_of)]
+#![feature(iter_map_windows)]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(fuzzy_provenance_casts)]
diff --git a/library/core/tests/manually_drop.rs b/library/core/tests/manually_drop.rs
index 22d72d219..bbf444471 100644
--- a/library/core/tests/manually_drop.rs
+++ b/library/core/tests/manually_drop.rs
@@ -1,4 +1,4 @@
-#![cfg_attr(not(bootstrap), allow(undropped_manually_drops))]
+#![allow(undropped_manually_drops)]
use core::mem::ManuallyDrop;
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 88f54591b..865e702b5 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -2278,11 +2278,39 @@ fn test_copy_within_panics_src_out_of_bounds() {
fn test_is_sorted() {
let empty: [i32; 0] = [];
+ // Tests on integers
assert!([1, 2, 2, 9].is_sorted());
assert!(![1, 3, 2].is_sorted());
assert!([0].is_sorted());
+ assert!([0, 0].is_sorted());
assert!(empty.is_sorted());
+
+ // Tests on floats
+ assert!([1.0f32, 2.0, 2.0, 9.0].is_sorted());
+ assert!(![1.0f32, 3.0f32, 2.0f32].is_sorted());
+ assert!([0.0f32].is_sorted());
+ assert!([0.0f32, 0.0f32].is_sorted());
+ // Test cases with NaNs
+ assert!([f32::NAN].is_sorted());
+ assert!(![f32::NAN, f32::NAN].is_sorted());
assert!(![0.0, 1.0, f32::NAN].is_sorted());
+ // Tests from <https://github.com/rust-lang/rust/pull/55045#discussion_r229689884>
+ assert!(![f32::NAN, f32::NAN, f32::NAN].is_sorted());
+ assert!(![1.0, f32::NAN, 2.0].is_sorted());
+ assert!(![2.0, f32::NAN, 1.0].is_sorted());
+ assert!(![2.0, f32::NAN, 1.0, 7.0].is_sorted());
+ assert!(![2.0, f32::NAN, 1.0, 0.0].is_sorted());
+ assert!(![-f32::NAN, -1.0, 0.0, 1.0, f32::NAN].is_sorted());
+ assert!(![f32::NAN, -f32::NAN, -1.0, 0.0, 1.0].is_sorted());
+ assert!(![1.0, f32::NAN, -f32::NAN, -1.0, 0.0].is_sorted());
+ assert!(![0.0, 1.0, f32::NAN, -f32::NAN, -1.0].is_sorted());
+ assert!(![-1.0, 0.0, 1.0, f32::NAN, -f32::NAN].is_sorted());
+
+ // Tests for is_sorted_by
+ assert!(![6, 2, 8, 5, 1, -60, 1337].is_sorted());
+ assert!([6, 2, 8, 5, 1, -60, 1337].is_sorted_by(|_, _| Some(Ordering::Less)));
+
+ // Tests for is_sorted_by_key
assert!([-2, -1, 0, 3].is_sorted());
assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
assert!(!["c", "bb", "aaa"].is_sorted());