diff options
Diffstat (limited to 'library/core/src')
| -rw-r--r-- | library/core/src/any.rs | 587 | ||||
| -rw-r--r-- | library/core/src/ascii/ascii_char.rs | 4 | ||||
| -rw-r--r-- | library/core/src/cmp.rs | 16 | ||||
| -rw-r--r-- | library/core/src/error.rs | 745 | ||||
| -rw-r--r-- | library/core/src/escape.rs | 4 | ||||
| -rw-r--r-- | library/core/src/ffi/c_str.rs | 16 | ||||
| -rw-r--r-- | library/core/src/ffi/mod.rs | 3 | ||||
| -rw-r--r-- | library/core/src/intrinsics.rs | 2 | ||||
| -rw-r--r-- | library/core/src/iter/adapters/map_windows.rs | 293 | ||||
| -rw-r--r-- | library/core/src/iter/adapters/mod.rs | 4 | ||||
| -rw-r--r-- | library/core/src/iter/mod.rs | 2 | ||||
| -rw-r--r-- | library/core/src/iter/traits/iterator.rs | 160 | ||||
| -rw-r--r-- | library/core/src/lib.rs | 2 | ||||
| -rw-r--r-- | library/core/src/marker.rs | 10 | ||||
| -rw-r--r-- | library/core/src/num/uint_macros.rs | 12 | ||||
| -rw-r--r-- | library/core/src/panicking.rs | 14 | ||||
| -rw-r--r-- | library/core/src/ptr/const_ptr.rs | 16 | ||||
| -rw-r--r-- | library/core/src/ptr/mut_ptr.rs | 15 | ||||
| -rw-r--r-- | library/core/src/str/mod.rs | 7 |
19 files changed, 1206 insertions, 706 deletions
diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 277c2f76a08..8f5404d9713 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")] @@ -798,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/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index f093a0990d1..5378b210e67 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/cmp.rs b/library/core/src/cmp.rs index faf48ae570f..3c127efb390 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/error.rs b/library/core/src/error.rs index 11cb0827578..1170221c10c 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 3d471419bb8..24bb9ad1ad1 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 b59ec12790d..92e38df4049 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 diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 3fcd5e7c1cb..b2c9a0800c9 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -110,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/intrinsics.rs b/library/core/src/intrinsics.rs index 9ef2c7cde02..676d4f2f38c 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. //! 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 00000000000..3c0e80b2559 --- /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 8cc2b7cec41..6f4fa7010f4 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 be04dfe042e..ca977d1ef82 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -440,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/iterator.rs b/library/core/src/iter/traits/iterator.rs index cecc120a6e2..ac1fc26a1ef 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 diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index ded799160bf..48c3c1f2123 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( diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 5ec751e5168..aec287226a0 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -76,8 +76,11 @@ macro marker_impls { #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Send")] #[rustc_on_unimplemented( + on(_Self = "std::rc::Rc<T, A>", note = "use `std::sync::Arc` instead of `std::rc::Rc`"), message = "`{Self}` cannot be sent between threads safely", - label = "`{Self}` cannot be sent between threads safely" + label = "`{Self}` cannot be sent between threads safely", + note = "consider using `std::sync::Arc<{Self}>`; for more information visit \ + <https://doc.rust-lang.org/book/ch16-03-shared-state.html>" )] pub unsafe auto trait Send { // empty. @@ -628,8 +631,11 @@ impl<T: ?Sized> Copy for &T {} any(_Self = "core::cell::RefCell<T>", _Self = "std::cell::RefCell<T>"), note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead", ), + on(_Self = "std::rc::Rc<T, A>", note = "use `std::sync::Arc` instead of `std::rc::Rc`"), message = "`{Self}` cannot be shared between threads safely", - label = "`{Self}` cannot be shared between threads safely" + label = "`{Self}` cannot be shared between threads safely", + note = "consider using `std::sync::Arc<{Self}>`; for more information visit \ + <https://doc.rust-lang.org/book/ch16-03-shared-state.html>" )] pub unsafe auto trait Sync { // FIXME(estebank): once support to add notes in `rustc_on_unimplemented` diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 6f6b6dbb80b..2136d29255f 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2074,10 +2074,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 = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_roundings1", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2109,11 +2109,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 = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_roundings1", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2134,13 +2134,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 = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "int_roundings1", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index f0fcdab00ad..7b6249207fe 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 74046a9c7c3..ee69d89a4b7 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 { @@ -55,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 _ @@ -995,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/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index e3a3f69afd9..9dbb3f9d322 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 { @@ -111,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 _ @@ -1095,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/str/mod.rs b/library/core/src/str/mod.rs index 71c03f7bfc5..e5f34952c7d 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] |
