diff options
Diffstat (limited to 'library/core')
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()); |