From 5dcc418f62e14580a319b2b8ec24645abbc1569e Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Fri, 17 Jun 2022 19:46:01 -0700 Subject: [PATCH 01/20] Document the conditional existence of `alloc::sync` and `alloc::task`. The wording is copied from `std::sync::atomic::AtomicPtr`, with additional advice on how to `#[cfg]` for it. --- library/alloc/src/sync.rs | 9 +++++++++ library/alloc/src/task.rs | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 55d51e0a3c4cf..d91217f341abd 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -3,6 +3,10 @@ //! Thread-safe reference-counting pointers. //! //! See the [`Arc`][Arc] documentation for more details. +//! +//! **Note**: This module is only available on platforms that support atomic +//! loads and stores of pointers. This may be detected at compile time using +//! `#[cfg(target_has_atomic = "ptr")]`. use core::any::Any; use core::borrow; @@ -82,6 +86,11 @@ macro_rules! acquire { /// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic] /// types. /// +/// **Note**: This type is only available on platforms that support atomic +/// loads and stores of pointers, which includes all platforms that support +/// the `std` crate but not all those which only support [`alloc`](crate). +/// This may be detected at compile time using `#[cfg(target_has_atomic = "ptr")]`. +/// /// ## Thread Safety /// /// Unlike [`Rc`], `Arc` uses atomic operations for its reference diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 528ee4ff1542c..9d8e309a978d9 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -1,5 +1,11 @@ #![stable(feature = "wake_trait", since = "1.51.0")] + //! Types and Traits for working with asynchronous tasks. +//! +//! **Note**: This module is only available on platforms that support atomic +//! loads and stores of pointers. This may be detected at compile time using +//! `#[cfg(target_has_atomic = "ptr")]`. + use core::mem::ManuallyDrop; use core::task::{RawWaker, RawWakerVTable, Waker}; From 9cd66be2351099d2a74aeb67ccb13e148dfdf114 Mon Sep 17 00:00:00 2001 From: Duarte Nunes Date: Wed, 13 Jul 2022 14:22:50 -0300 Subject: [PATCH 02/20] docs: be less harsh in wording for Vec::from_raw_parts In particular, be clear that it is sound to specify memory not originating from a previous `Vec` allocation. That is already suggested in other parts of the documentation about zero-alloc conversions to Box<[T]>. Incorporate a constraint from `slice::from_raw_parts` that was missing but needs to be fulfilled, since a `Vec` can be converted into a slice. --- library/alloc/src/vec/mod.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index fa9f2131c0c1d..aa822b1f923df 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -490,8 +490,6 @@ impl Vec { /// This is highly unsafe, due to the number of invariants that aren't /// checked: /// - /// * `ptr` needs to have been previously allocated via [`String`]/`Vec` - /// (at least, it's highly likely to be incorrect if it wasn't). /// * `T` needs to have the same alignment as what `ptr` was allocated with. /// (`T` having a less strict alignment is not sufficient, the alignment really /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be @@ -500,6 +498,12 @@ impl Vec { /// to be the same size as the pointer was allocated with. (Because similar to /// alignment, [`dealloc`] must be called with the same layout `size`.) /// * `length` needs to be less than or equal to `capacity`. + /// * `capacity` needs to be the capacity that the pointer was allocated with. + /// * The allocated size in bytes must be no larger than `isize::MAX`. + /// See the safety documentation of [`pointer::offset`]. + /// + /// To ensure these requirements are easily met, ensure `ptr` has previously + /// been allocated via `Vec`. /// /// Violating these may cause problems like corrupting the allocator's /// internal data structures. For example it is normally **not** safe @@ -648,14 +652,20 @@ impl Vec { /// This is highly unsafe, due to the number of invariants that aren't /// checked: /// - /// * `ptr` needs to have been previously allocated via [`String`]/`Vec` - /// (at least, it's highly likely to be incorrect if it wasn't). - /// * `T` needs to have the same size and alignment as what `ptr` was allocated with. + /// * `T` needs to have the same alignment as what `ptr` was allocated with. /// (`T` having a less strict alignment is not sufficient, the alignment really /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// allocated and deallocated with the same layout.) + /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs + /// to be the same size as the pointer was allocated with. (Because similar to + /// alignment, [`dealloc`] must be called with the same layout `size`.) /// * `length` needs to be less than or equal to `capacity`. /// * `capacity` needs to be the capacity that the pointer was allocated with. + /// * The allocated size in bytes must be no larger than `isize::MAX`. + /// See the safety documentation of [`pointer::offset`]. + /// + /// To ensure these requirements are easily met, ensure `ptr` has previously + /// been allocated via `Vec`. /// /// Violating these may cause problems like corrupting the allocator's /// internal data structures. For example it is **not** safe From c9ec7aa0d7013bab63477adc77a94163a0df2c32 Mon Sep 17 00:00:00 2001 From: Duarte Nunes Date: Wed, 13 Jul 2022 19:46:04 -0300 Subject: [PATCH 03/20] changes to wording --- library/alloc/src/vec/mod.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index aa822b1f923df..17342cacd760e 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -483,7 +483,7 @@ impl Vec { Self::with_capacity_in(capacity, Global) } - /// Creates a `Vec` directly from the raw components of another vector. + /// Creates a `Vec` directly from a pointer, a capacity, and a length. /// /// # Safety /// @@ -498,12 +498,14 @@ impl Vec { /// to be the same size as the pointer was allocated with. (Because similar to /// alignment, [`dealloc`] must be called with the same layout `size`.) /// * `length` needs to be less than or equal to `capacity`. + /// * The first `length` values must be properly initialized values of type `T`. /// * `capacity` needs to be the capacity that the pointer was allocated with. - /// * The allocated size in bytes must be no larger than `isize::MAX`. + /// * The allocated size in bytes must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// - /// To ensure these requirements are easily met, ensure `ptr` has previously - /// been allocated via `Vec`. + /// These requirements are always uphead by any `ptr` that has been allocated + /// via `Vec`. Other allocation sources are allowed if the invariants are + /// upheld. /// /// Violating these may cause problems like corrupting the allocator's /// internal data structures. For example it is normally **not** safe @@ -645,7 +647,8 @@ impl Vec { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } - /// Creates a `Vec` directly from the raw components of another vector. + /// Creates a `Vec` directly from a pointer, a capacity, a length, + /// and an allocator. /// /// # Safety /// @@ -660,12 +663,14 @@ impl Vec { /// to be the same size as the pointer was allocated with. (Because similar to /// alignment, [`dealloc`] must be called with the same layout `size`.) /// * `length` needs to be less than or equal to `capacity`. - /// * `capacity` needs to be the capacity that the pointer was allocated with. - /// * The allocated size in bytes must be no larger than `isize::MAX`. + /// * The first `length` values must be properly initialized values of type `T`. + /// * `capacity` needs to [fit] the layout size that the pointer was allocated with. + /// * The allocated size in bytes must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// - /// To ensure these requirements are easily met, ensure `ptr` has previously - /// been allocated via `Vec`. + /// These requirements are always uphead by any `ptr` that has been allocated + /// via `Vec`. Other allocation sources are allowed if the invariants are + /// upheld. /// /// Violating these may cause problems like corrupting the allocator's /// internal data structures. For example it is **not** safe @@ -683,6 +688,7 @@ impl Vec { /// /// [`String`]: crate::string::String /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc + /// [*fit*]: crate::alloc::Allocator#memory-fitting /// /// # Examples /// From 050115c0d4115fb31c056ae858384ef48a77239d Mon Sep 17 00:00:00 2001 From: Duarte Nunes Date: Wed, 13 Jul 2022 21:49:31 -0300 Subject: [PATCH 04/20] typo --- library/alloc/src/vec/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 17342cacd760e..6b544c7025007 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -503,7 +503,7 @@ impl Vec { /// * The allocated size in bytes must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// - /// These requirements are always uphead by any `ptr` that has been allocated + /// These requirements are always upheld by any `ptr` that has been allocated /// via `Vec`. Other allocation sources are allowed if the invariants are /// upheld. /// @@ -668,7 +668,7 @@ impl Vec { /// * The allocated size in bytes must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// - /// These requirements are always uphead by any `ptr` that has been allocated + /// These requirements are always upheld by any `ptr` that has been allocated /// via `Vec`. Other allocation sources are allowed if the invariants are /// upheld. /// From 8d35ab38067ede0b2816e0177d1d0e0869e89136 Mon Sep 17 00:00:00 2001 From: Duarte Nunes Date: Wed, 13 Jul 2022 22:04:15 -0300 Subject: [PATCH 05/20] rustdoc --- library/alloc/src/vec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6b544c7025007..fcfb88b18c7e9 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -664,7 +664,7 @@ impl Vec { /// alignment, [`dealloc`] must be called with the same layout `size`.) /// * `length` needs to be less than or equal to `capacity`. /// * The first `length` values must be properly initialized values of type `T`. - /// * `capacity` needs to [fit] the layout size that the pointer was allocated with. + /// * `capacity` needs to [*fit*] the layout size that the pointer was allocated with. /// * The allocated size in bytes must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// From a85ee3ed9130de6b263de0b05e67b04e644f269e Mon Sep 17 00:00:00 2001 From: Duarte Nunes Date: Thu, 14 Jul 2022 11:47:06 -0300 Subject: [PATCH 06/20] add code examples --- library/alloc/src/vec/mod.rs | 51 +++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index fcfb88b18c7e9..ae99772450e21 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -557,6 +557,32 @@ impl Vec { /// assert_eq!(rebuilt, [4, 5, 6]); /// } /// ``` + /// + /// Using memory that was allocated elsewhere: + /// + /// ```rust + /// #![feature(allocator_api)] + /// + /// use std::alloc::{AllocError, Allocator, Global, Layout}; + /// + /// fn main() { + /// let layout = Layout::array::(16).expect("overflow cannot happen"); + /// + /// let vec = unsafe { + /// let mem = match Global.allocate(layout) { + /// Ok(mem) => mem.cast::().as_ptr(), + /// Err(AllocError) => return, + /// }; + /// + /// mem.write(1_000_000); + /// + /// Vec::from_raw_parts_in(mem, 1, 16, Global) + /// }; + /// + /// assert_eq!(vec, &[1_000_000]); + /// assert_eq!(vec.capacity(), 16); + /// } + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self { @@ -669,7 +695,7 @@ impl Vec { /// See the safety documentation of [`pointer::offset`]. /// /// These requirements are always upheld by any `ptr` that has been allocated - /// via `Vec`. Other allocation sources are allowed if the invariants are + /// via `Vec`. Other allocation sources are allowed if the invariants are /// upheld. /// /// Violating these may cause problems like corrupting the allocator's @@ -727,6 +753,29 @@ impl Vec { /// assert_eq!(rebuilt, [4, 5, 6]); /// } /// ``` + /// + /// Using memory that was allocated elsewhere: + /// + /// ```rust + /// use std::alloc::{alloc, Layout}; + /// + /// fn main() { + /// let layout = Layout::array::(16).expect("overflow cannot happen"); + /// let vec = unsafe { + /// let mem = alloc(layout).cast::(); + /// if mem.is_null() { + /// return; + /// } + /// + /// mem.write(1_000_000); + /// + /// Vec::from_raw_parts(mem, 1, 16) + /// }; + /// + /// assert_eq!(vec, &[1_000_000]); + /// assert_eq!(vec.capacity(), 16); + /// } + /// ``` #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self { From 551d921de0f13c54093ab4f6a3adbe69292e091a Mon Sep 17 00:00:00 2001 From: Jan Behrens Date: Tue, 19 Jul 2022 11:40:40 +0200 Subject: [PATCH 07/20] docs: Improve AsRef / AsMut docs on blanket impls - Explicitly mention that `AsRef` and `AsMut` do not auto-dereference generally for all dereferencable types (but only if inner type is a shared and/or mutable reference) - Give advice to not use `AsRef` or `AsMut` for the sole purpose of dereferencing - Suggest providing a transitive `AsRef` or `AsMut` implementation for types which implement `Deref` - Add new section "Reflexivity" in documentation comments for `AsRef` and `AsMut` - Provide better example for `AsMut` - Added heading "Relation to `Borrow`" in `AsRef`'s docs to improve structure Issue #45742 and a corresponding FIXME in the libcore suggest that `AsRef` and `AsMut` should provide a blanket implementation over `Deref`. As that is difficult to realize at the moment, this commit updates the documentation to better describe the status-quo and to give advice on how to use `AsRef` and `AsMut`. --- library/core/src/convert/mod.rs | 177 ++++++++++++++++++++++++++++---- 1 file changed, 159 insertions(+), 18 deletions(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index b30c8a4aeabdd..dd0d6478c3a20 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -25,6 +25,7 @@ //! # Generic Implementations //! //! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference +//! (but not generally for all [dereferenceable types][core::ops::Deref]) //! - [`From`]` for T` implies [`Into`]` for U` //! - [`TryFrom`]` for T` implies [`TryInto`]` for U` //! - [`From`] and [`Into`] are reflexive, which means that all types can @@ -108,10 +109,12 @@ pub const fn identity(x: T) -> T { /// If you need to do a costly conversion it is better to implement [`From`] with type /// `&T` or write a custom function. /// +/// # Relation to `Borrow` +/// /// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in a few aspects: /// /// - Unlike `AsRef`, [`Borrow`] has a blanket impl for any `T`, and can be used to accept either -/// a reference or a value. +/// a reference or a value. (See also note on `AsRef`'s reflexibility below.) /// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for a borrowed value are /// equivalent to those of the owned value. For this reason, if you want to /// borrow only a single field of a struct you can implement `AsRef`, but not [`Borrow`]. @@ -121,9 +124,55 @@ pub const fn identity(x: T) -> T { /// /// # Generic Implementations /// -/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable -/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type -/// `&mut Foo` or `&&mut Foo`) +/// `AsRef` auto-dereferences if the inner type is a reference or a mutable reference +/// (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`). +/// +/// Note that due to historic reasons, the above currently does not hold generally for all +/// [dereferenceable types], e.g. `foo.as_ref()` will *not* work the same as +/// `Box::new(foo).as_ref()`. Instead, many smart pointers provide an `as_ref` implementation which +/// simply returns a reference to the [pointed-to value] (but do not perform a cheap +/// reference-to-reference conversion for that value). However, [`AsRef::as_ref`] should not be +/// used for the sole purpose of dereferencing; instead ['`Deref` coercion'] can be used: +/// +/// [dereferenceable types]: core::ops::Deref +/// [pointed-to value]: core::ops::Deref::Target +/// ['`Deref` coercion']: core::ops::Deref#more-on-deref-coercion +/// +/// ``` +/// let x = Box::new(5i32); +/// // Avoid this: +/// // let y: &i32 = x.as_ref(); +/// // Better just write: +/// let y: &i32 = &x; +/// ``` +/// +/// Types which implement [`Deref`][core::ops::Deref] should consider implementing `AsRef` as +/// follows: +/// +/// ``` +/// impl AsRef for SomeType +/// where +/// T: ?Sized, +/// ::Target: AsRef, +/// { +/// fn as_ref(&self) -> &T { +/// self.deref().as_ref() +/// } +/// } +/// ``` +/// +/// # Reflexivity +/// +/// Ideally, `AsRef` would be reflexive, that is there is an `impl AsRef for T`, with +/// [`as_ref`][AsRef::as_ref] simply returning its argument unchanged. +/// Such a blanket implementation is currently *not* provided due to technical restrictions of +/// Rust's type system (it would be overlapping with another existing blanket implementation for +/// `&T where T: AsRef` which allows `AsRef` to auto-dereference, see "Generic Implementations" +/// above). +/// +/// A trivial implementation of `AsRef for T` must be added explicitly for a particular type `T` +/// where needed or desired. Note, however, that not all types from `std` contain such an +/// implementation, and those cannot be added by external code due to orphan rules. /// /// # Examples /// @@ -170,29 +219,121 @@ pub trait AsRef { /// /// # Generic Implementations /// -/// - `AsMut` auto-dereferences if the inner type is a mutable reference -/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo` -/// or `&mut &mut Foo`) +/// `AsMut` auto-dereferences if the inner type is a mutable reference +/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo` or `&mut &mut Foo`). +/// +/// Note that due to historic reasons, the above currently does not hold generally for all +/// [mutably dereferenceable types], e.g. `foo.as_mut()` will *not* work the same as +/// `Box::new(foo).as_mut()`. Instead, many smart pointers provide an `as_mut` implementation which +/// simply returns a reference to the [pointed-to value] (but do not perform a cheap +/// reference-to-reference conversion for that value). However, [`AsMut::as_mut`] should not be +/// used for the sole purpose of mutable dereferencing; instead ['`Deref` coercion'] can be used: +/// +/// [mutably dereferenceable types]: core::ops::DerefMut +/// [pointed-to value]: core::ops::Deref::Target +/// ['`Deref` coercion']: core::ops::DerefMut#more-on-deref-coercion +/// +/// ``` +/// let mut x = Box::new(5i32); +/// // Avoid this: +/// // let y: &mut i32 = x.as_mut(); +/// // Better just write: +/// let y: &mut i32 = &mut x; +/// ``` +/// +/// Types which implement [`DerefMut`](core::ops::DerefMut) should consider to add an +/// implementation of `AsMut` as follows: +/// +/// ``` +/// impl AsMut for SomeType +/// where +/// ::Target: AsMut, +/// { +/// fn as_mut(&mut self) -> &mut T { +/// self.deref_mut().as_mut() +/// } +/// } +/// ``` +/// +/// # Reflexivity +/// +/// Ideally, `AsMut` would be reflexive, that is there is an `impl AsMut for T`, with +/// [`as_mut`][AsMut::as_mut] simply returning its argument unchanged. +/// Such a blanket implementation is currently *not* provided due to technical restrictions of +/// Rust's type system (it would be overlapping with another existing blanket implementation for +/// `&mut T where T: AsMut` which allows `AsMut` to auto-dereference, see "Generic +/// Implementations" above). +/// +/// A trivial implementation of `AsMut for T` must be added explicitly for a particular type `T` +/// where needed or desired. Note, however, that not all types from `std` contain such an +/// implementation, and those cannot be added by external code due to orphan rules. /// /// # Examples /// -/// Using `AsMut` as trait bound for a generic function we can accept all mutable references -/// that can be converted to type `&mut T`. Because [`Box`] implements `AsMut` we can -/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`. -/// Because [`Box`] implements `AsMut`, `add_one` accepts arguments of type -/// `&mut Box` as well: +/// Using `AsMut` as trait bound for a generic function, we can accept all mutable references that +/// can be converted to type `&mut T`. Unlike [dereference], which has a single [target type], +/// there can be multiple implementations of `AsMut` for a type. In particular, `Vec` implements +/// both `AsMut>` and `AsMut<[T]>`. +/// +/// In the following, the example functions `caesar` and `null_terminate` provide a generic +/// interface which work with any type that can be converted by cheap mutable-to-mutable conversion +/// into a byte slice or byte `Vec`, respectively. +/// +/// [dereference]: core::ops::DerefMut +/// [target type]: core::ops::Deref::Target /// /// ``` -/// fn add_one>(num: &mut T) { -/// *num.as_mut() += 1; +/// struct Document { +/// info: String, +/// content: Vec, /// } /// -/// let mut boxed_num = Box::new(0); -/// add_one(&mut boxed_num); -/// assert_eq!(*boxed_num, 1); +/// impl AsMut for Document +/// where +/// Vec: AsMut, +/// { +/// fn as_mut(&mut self) -> &mut T { +/// self.content.as_mut() +/// } +/// } +/// +/// fn caesar>(data: &mut T, key: u8) { +/// for byte in data.as_mut() { +/// *byte = byte.wrapping_add(key); +/// } +/// } +/// +/// fn null_terminate>>(data: &mut T) { +/// // Using a non-generic inner function, which contains most of the +/// // functionality, helps to minimize monomorphization overhead. +/// fn doit(data: &mut Vec) { +/// let len = data.len(); +/// if len == 0 || data[len-1] != 0 { +/// data.push(0); +/// } +/// } +/// doit(data.as_mut()); +/// } +/// +/// fn main() { +/// let mut v: Vec = vec![1, 2, 3]; +/// caesar(&mut v, 5); +/// assert_eq!(v, [6, 7, 8]); +/// null_terminate(&mut v); +/// assert_eq!(v, [6, 7, 8, 0]); +/// let mut doc = Document { +/// info: String::from("Example"), +/// content: vec![17, 19, 8], +/// }; +/// caesar(&mut doc, 1); +/// assert_eq!(doc.content, [18, 20, 9]); +/// null_terminate(&mut doc); +/// assert_eq!(doc.content, [18, 20, 9, 0]); +/// } /// ``` /// -/// [`Box`]: ../../std/boxed/struct.Box.html +/// Note, however, that APIs don't need to be generic. In many cases taking a `&mut [u8]` or +/// `&mut Vec`, for example, is the better choice (callers need to pass the correct type then). #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")] pub trait AsMut { From 9f68e3ef1b3bc0a7f1ce4d7ff7fc74bcaa2d42ad Mon Sep 17 00:00:00 2001 From: Jan Behrens Date: Tue, 19 Jul 2022 23:24:51 +0200 Subject: [PATCH 08/20] fixup! docs: Improve AsRef / AsMut docs on blanket impls Fixed examples in sections "Generic Implementations" of `AsRef`'s and `AsMut`'s doc comments, which failed tests. --- library/core/src/convert/mod.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index dd0d6478c3a20..e75e32855d1bb 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -150,6 +150,14 @@ pub const fn identity(x: T) -> T { /// follows: /// /// ``` +/// # use core::ops::Deref; +/// # struct SomeType; +/// # impl Deref for SomeType { +/// # type Target = [u8]; +/// # fn deref(&self) -> &[u8] { +/// # &[] +/// # } +/// # } /// impl AsRef for SomeType /// where /// T: ?Sized, @@ -245,6 +253,19 @@ pub trait AsRef { /// implementation of `AsMut` as follows: /// /// ``` +/// # use core::ops::{Deref, DerefMut}; +/// # struct SomeType; +/// # impl Deref for SomeType { +/// # type Target = [u8]; +/// # fn deref(&self) -> &[u8] { +/// # &[] +/// # } +/// # } +/// # impl DerefMut for SomeType { +/// # fn deref_mut(&mut self) -> &mut [u8] { +/// # &mut [] +/// # } +/// # } /// impl AsMut for SomeType /// where /// ::Target: AsMut, From e4a259b5e480ea5b444384f9ff9cd862a46a9d16 Mon Sep 17 00:00:00 2001 From: Jan Behrens Date: Tue, 19 Jul 2022 23:53:40 +0200 Subject: [PATCH 09/20] fixup! docs: Improve AsRef / AsMut docs on blanket impls Better conform to Rust API Documentation Conventions --- library/core/src/convert/mod.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index e75e32855d1bb..bdd862f39c801 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -146,8 +146,9 @@ pub const fn identity(x: T) -> T { /// let y: &i32 = &x; /// ``` /// -/// Types which implement [`Deref`][core::ops::Deref] should consider implementing `AsRef` as -/// follows: +/// Types which implement [`Deref`] should consider implementing `AsRef` as follows: +/// +/// [`Deref`]: core::ops::Deref /// /// ``` /// # use core::ops::Deref; @@ -172,12 +173,14 @@ pub const fn identity(x: T) -> T { /// # Reflexivity /// /// Ideally, `AsRef` would be reflexive, that is there is an `impl AsRef for T`, with -/// [`as_ref`][AsRef::as_ref] simply returning its argument unchanged. +/// [`as_ref`] simply returning its argument unchanged. /// Such a blanket implementation is currently *not* provided due to technical restrictions of /// Rust's type system (it would be overlapping with another existing blanket implementation for /// `&T where T: AsRef` which allows `AsRef` to auto-dereference, see "Generic Implementations" /// above). /// +/// [`as_ref`]: AsRef::as_ref +/// /// A trivial implementation of `AsRef for T` must be added explicitly for a particular type `T` /// where needed or desired. Note, however, that not all types from `std` contain such an /// implementation, and those cannot be added by external code due to orphan rules. @@ -249,8 +252,10 @@ pub trait AsRef { /// let y: &mut i32 = &mut x; /// ``` /// -/// Types which implement [`DerefMut`](core::ops::DerefMut) should consider to add an -/// implementation of `AsMut` as follows: +/// Types which implement [`DerefMut`] should consider to add an implementation of `AsMut` as +/// follows: +/// +/// [`DerefMut`]: core::ops::DerefMut /// /// ``` /// # use core::ops::{Deref, DerefMut}; @@ -279,12 +284,14 @@ pub trait AsRef { /// # Reflexivity /// /// Ideally, `AsMut` would be reflexive, that is there is an `impl AsMut for T`, with -/// [`as_mut`][AsMut::as_mut] simply returning its argument unchanged. +/// [`as_mut`] simply returning its argument unchanged. /// Such a blanket implementation is currently *not* provided due to technical restrictions of /// Rust's type system (it would be overlapping with another existing blanket implementation for /// `&mut T where T: AsMut` which allows `AsMut` to auto-dereference, see "Generic /// Implementations" above). /// +/// [`as_mut`]: AsMut::as_mut +/// /// A trivial implementation of `AsMut for T` must be added explicitly for a particular type `T` /// where needed or desired. Note, however, that not all types from `std` contain such an /// implementation, and those cannot be added by external code due to orphan rules. @@ -298,7 +305,7 @@ pub trait AsRef { /// /// In the following, the example functions `caesar` and `null_terminate` provide a generic /// interface which work with any type that can be converted by cheap mutable-to-mutable conversion -/// into a byte slice or byte `Vec`, respectively. +/// into a byte slice (`[u8]`) or byte vector (`Vec`), respectively. /// /// [dereference]: core::ops::DerefMut /// [target type]: core::ops::Deref::Target From e6b761b902fe80ba454368d078fb834554981109 Mon Sep 17 00:00:00 2001 From: Jan Behrens Date: Thu, 21 Jul 2022 16:40:14 +0200 Subject: [PATCH 10/20] fixup! docs: Improve AsRef / AsMut docs on blanket impls Changed wording in sections on "Reflexivity": replaced "that is there is" with "i.e. there would be" and removed comma before "with" Reason: "there is" somewhat contradicted the "would be" hypothetical. A slightly redundant wording has now been chosen for better clarity. The comma seemed to be superfluous. --- library/core/src/convert/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index bdd862f39c801..e2be262e311d6 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -172,8 +172,8 @@ pub const fn identity(x: T) -> T { /// /// # Reflexivity /// -/// Ideally, `AsRef` would be reflexive, that is there is an `impl AsRef for T`, with -/// [`as_ref`] simply returning its argument unchanged. +/// Ideally, `AsRef` would be reflexive, i.e. there would be an `impl AsRef for T` +/// with [`as_ref`] simply returning its argument unchanged. /// Such a blanket implementation is currently *not* provided due to technical restrictions of /// Rust's type system (it would be overlapping with another existing blanket implementation for /// `&T where T: AsRef` which allows `AsRef` to auto-dereference, see "Generic Implementations" @@ -283,8 +283,8 @@ pub trait AsRef { /// /// # Reflexivity /// -/// Ideally, `AsMut` would be reflexive, that is there is an `impl AsMut for T`, with -/// [`as_mut`] simply returning its argument unchanged. +/// Ideally, `AsMut` would be reflexive, i.e. there would be an `impl AsMut for T` +/// with [`as_mut`] simply returning its argument unchanged. /// Such a blanket implementation is currently *not* provided due to technical restrictions of /// Rust's type system (it would be overlapping with another existing blanket implementation for /// `&mut T where T: AsMut` which allows `AsMut` to auto-dereference, see "Generic From 698a3c679811fbde878148e742a6db591a13d89e Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 13 Aug 2022 02:08:24 +0200 Subject: [PATCH 11/20] Tweak `FpCategory` example order. --- library/core/src/num/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index f481399fdcf92..fce52a54949b6 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -936,8 +936,8 @@ impl usize { /// assert_eq!(num.classify(), FpCategory::Normal); /// assert_eq!(inf.classify(), FpCategory::Infinite); /// assert_eq!(zero.classify(), FpCategory::Zero); -/// assert_eq!(nan.classify(), FpCategory::Nan); /// assert_eq!(sub.classify(), FpCategory::Subnormal); +/// assert_eq!(nan.classify(), FpCategory::Nan); /// ``` #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] From cb86c38cdbf29a400dd48ec8450ce71b81c8dd45 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Fri, 26 Aug 2022 14:59:12 +0200 Subject: [PATCH 12/20] Fix `#[derive(Default)]` on a generic `#[default]` enum adding unnecessary `Default` bounds --- .../src/deriving/bounds.rs | 1 + .../src/deriving/clone.rs | 1 + .../src/deriving/cmp/eq.rs | 1 + .../src/deriving/cmp/ord.rs | 1 + .../src/deriving/cmp/partial_eq.rs | 1 + .../src/deriving/cmp/partial_ord.rs | 1 + .../src/deriving/debug.rs | 1 + .../src/deriving/decodable.rs | 1 + .../src/deriving/default.rs | 20 +++++++++++++++++++ .../src/deriving/encodable.rs | 1 + .../src/deriving/generic/mod.rs | 6 +++++- .../rustc_builtin_macros/src/deriving/hash.rs | 1 + 12 files changed, 35 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 77e0b6c55a80e..7bd344467d032 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -16,6 +16,7 @@ pub fn expand_deriving_copy( let trait_def = TraitDef { span, path: path_std!(marker::Copy), + skip_path_as_bound: false, additional_bounds: Vec::new(), generics: Bounds::empty(), supports_unions: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index c7f2d95e72f0c..fa8685f5f4e56 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -72,6 +72,7 @@ pub fn expand_deriving_clone( let trait_def = TraitDef { span, path: path_std!(clone::Clone), + skip_path_as_bound: false, additional_bounds: bounds, generics: Bounds::empty(), supports_unions: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 5b556c5c9b9d1..eab67b0d354cf 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -25,6 +25,7 @@ pub fn expand_deriving_eq( let trait_def = TraitDef { span, path: path_std!(cmp::Eq), + skip_path_as_bound: false, additional_bounds: Vec::new(), generics: Bounds::empty(), supports_unions: true, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 7262586955811..7f117981a9a2f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -19,6 +19,7 @@ pub fn expand_deriving_ord( let trait_def = TraitDef { span, path: path_std!(cmp::Ord), + skip_path_as_bound: false, additional_bounds: Vec::new(), generics: Bounds::empty(), supports_unions: false, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 42ee65b570a2a..236cbccaf9fee 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -83,6 +83,7 @@ pub fn expand_deriving_partial_eq( let trait_def = TraitDef { span, path: path_std!(cmp::PartialEq), + skip_path_as_bound: false, additional_bounds: Vec::new(), generics: Bounds::empty(), supports_unions: false, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 516892aeda96f..4173403a1b84a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -37,6 +37,7 @@ pub fn expand_deriving_partial_ord( let trait_def = TraitDef { span, path: path_std!(cmp::PartialOrd), + skip_path_as_bound: false, additional_bounds: vec![], generics: Bounds::empty(), supports_unions: false, diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 4af7fd8165388..2cf614ed9476c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -20,6 +20,7 @@ pub fn expand_deriving_debug( let trait_def = TraitDef { span, path: path_std!(fmt::Debug), + skip_path_as_bound: false, additional_bounds: Vec::new(), generics: Bounds::empty(), supports_unions: false, diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 7174dbbe7ea8b..d669f616802fe 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -23,6 +23,7 @@ pub fn expand_deriving_rustc_decodable( let trait_def = TraitDef { span, path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), + skip_path_as_bound: false, additional_bounds: Vec::new(), generics: Bounds::empty(), supports_unions: false, diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index a94c8a996e642..17df9fb279ad6 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -24,6 +24,7 @@ pub fn expand_deriving_default( let trait_def = TraitDef { span, path: Path::new(vec![kw::Default, sym::Default]), + skip_path_as_bound: has_a_default_variant(item), additional_bounds: Vec::new(), generics: Bounds::empty(), supports_unions: false, @@ -262,3 +263,22 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, ' } } } + +fn has_a_default_variant(item: &Annotatable) -> bool { + struct HasDefaultAttrOnVariant { + found: bool, + } + + impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant { + fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) { + if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) { + self.found = true; + } + // no need to subrecurse. + } + } + + let mut visitor = HasDefaultAttrOnVariant { found: false }; + item.visit_with(&mut visitor); + visitor.found +} diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index b220e54238f46..f83f58b97d38f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -107,6 +107,7 @@ pub fn expand_deriving_rustc_encodable( let trait_def = TraitDef { span, path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), + skip_path_as_bound: false, additional_bounds: Vec::new(), generics: Bounds::empty(), supports_unions: false, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index adffebd3fd285..cd53050c61e68 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -172,6 +172,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use std::cell::RefCell; use std::iter; +use std::ops::Not; use std::vec; use thin_vec::thin_vec; use ty::{Bounds, Path, Ref, Self_, Ty}; @@ -185,6 +186,9 @@ pub struct TraitDef<'a> { /// Path of the trait, including any type parameters pub path: Path, + /// Whether to skip adding the current trait as a bound to the type parameters of the type. + pub skip_path_as_bound: bool, + /// Additional bounds required of any type parameters of the type, /// other than the current trait pub additional_bounds: Vec, @@ -594,7 +598,7 @@ impl<'a> TraitDef<'a> { cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)) }).chain( // require the current trait - iter::once(cx.trait_bound(trait_path.clone())) + self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone())) ).chain( // also add in any bounds from the declaration param.bounds.iter().cloned() diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index f1f02e7ce7787..6e9d5f08b9443 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -22,6 +22,7 @@ pub fn expand_deriving_hash( let hash_trait_def = TraitDef { span, path, + skip_path_as_bound: false, additional_bounds: Vec::new(), generics: Bounds::empty(), supports_unions: false, From 975e72fc0f122e2c2b57d8d61a9c6553d29fb366 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Fri, 26 Aug 2022 15:00:38 +0200 Subject: [PATCH 13/20] Add corresponding regression test --- src/test/ui/deriving/deriving-default-enum.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/ui/deriving/deriving-default-enum.rs b/src/test/ui/deriving/deriving-default-enum.rs index d1a81c72c2fdc..1c7a501edc705 100644 --- a/src/test/ui/deriving/deriving-default-enum.rs +++ b/src/test/ui/deriving/deriving-default-enum.rs @@ -12,6 +12,16 @@ enum Foo { Beta(NotDefault), } +// #[default] on a generic enum does not add `Default` bounds to the type params. +#[derive(Default)] +enum MyOption { + #[default] + None, + #[allow(dead_code)] + Some(T), +} + fn main() { assert_eq!(Foo::default(), Foo::Alpha); + assert!(matches!(MyOption::::default(), MyOption::None)); } From 3d4980bc8d8a58df217a6b659b9353a11ce4cd29 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Thu, 15 Sep 2022 18:56:12 +0200 Subject: [PATCH 14/20] Future-proof against loose bounds if default variant is non-exhaustive. Co-Authored-By: Mark Rousskov --- src/test/ui/macros/macros-nonfatal-errors.rs | 21 +++++++++++++++++++ .../ui/macros/macros-nonfatal-errors.stderr | 12 ++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/test/ui/macros/macros-nonfatal-errors.rs b/src/test/ui/macros/macros-nonfatal-errors.rs index e7a01f105de0b..140cc5b0fd808 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.rs +++ b/src/test/ui/macros/macros-nonfatal-errors.rs @@ -116,3 +116,24 @@ fn main() { trace_macros!(invalid); //~ ERROR } + +/// Check that `#[derive(Default)]` does use a `T : Default` bound when the +/// `#[default]` variant is `#[non_exhaustive]` (should this end up allowed). +const _: () = { + #[derive(Default)] + enum NonExhaustiveDefaultGeneric { + #[default] + #[non_exhaustive] + Foo, //~ ERROR default variant must be exhaustive + Bar(T), + } + + fn assert_impls_default() {} + + enum NotDefault {} + + // Note: the `derive(Default)` currently bails early enough for trait-checking + // not to happen. Should it bail late enough, or even pass, make sure to + // assert that the following line fails. + let _ = assert_impls_default::>; +}; diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr index b3c6d07f96763..d42f6c179b7ef 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.stderr +++ b/src/test/ui/macros/macros-nonfatal-errors.stderr @@ -215,11 +215,21 @@ error: trace_macros! accepts only `true` or `false` LL | trace_macros!(invalid); | ^^^^^^^^^^^^^^^^^^^^^^ +error: default variant must be exhaustive + --> $DIR/macros-nonfatal-errors.rs:127:9 + | +LL | #[non_exhaustive] + | ----------------- declared `#[non_exhaustive]` here +LL | Foo, + | ^^^ + | + = help: consider a manual implementation of `Default` + error: cannot find macro `llvm_asm` in this scope --> $DIR/macros-nonfatal-errors.rs:99:5 | LL | llvm_asm!(invalid); | ^^^^^^^^ -error: aborting due to 27 previous errors +error: aborting due to 28 previous errors From 591c1f25b297c446ac13211f955d06a859206f1a Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 27 Sep 2022 11:55:13 +0530 Subject: [PATCH 15/20] introduce `{char, u8}::is_ascii_octdigit` --- library/core/src/char/methods.rs | 32 ++++++++++++++++++++++++++++++++ library/core/src/lib.rs | 1 + library/core/src/num/mod.rs | 32 ++++++++++++++++++++++++++++++++ library/core/tests/ascii.rs | 18 ++++++++++++++++++ library/core/tests/lib.rs | 1 + 5 files changed, 84 insertions(+) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index b7a63b7c67566..224bc9effe61e 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1444,6 +1444,38 @@ impl char { matches!(*self, '0'..='9') } + /// Checks if the value is an ASCII octal digit: + /// U+0030 '0' ..= U+0037 '7'. + /// + /// # Examples + /// + /// ``` + /// #![feature(is_ascii_octdigit)] + /// + /// let uppercase_a = 'A'; + /// let a = 'a'; + /// let zero = '0'; + /// let seven = '7'; + /// let nine = '9'; + /// let percent = '%'; + /// let lf = '\n'; + /// + /// assert!(!uppercase_a.is_ascii_octdigit()); + /// assert!(!a.is_ascii_octdigit()); + /// assert!(zero.is_ascii_octdigit()); + /// assert!(seven.is_ascii_octdigit()); + /// assert!(!nine.is_ascii_octdigit()); + /// assert!(!percent.is_ascii_octdigit()); + /// assert!(!lf.is_ascii_octdigit()); + /// ``` + #[must_use] + #[unstable(feature = "is_ascii_octdigit", issue = "101288")] + #[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")] + #[inline] + pub const fn is_ascii_octdigit(&self) -> bool { + matches!(*self, '0'..='7') + } + /// Checks if the value is an ASCII hexadecimal digit: /// /// - U+0030 '0' ..= U+0039 '9', or diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5690b5256e88c..18ad0bdc8b20e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -164,6 +164,7 @@ #![feature(const_slice_index)] #![feature(const_is_char_boundary)] #![feature(const_cstr_methods)] +#![feature(is_ascii_octdigit)] // // Language features: #![feature(abi_unadjusted)] diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index c0be235c120bf..01642a8dd31a8 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -622,6 +622,38 @@ impl u8 { matches!(*self, b'0'..=b'9') } + /// Checks if the value is an ASCII octal digit: + /// U+0030 '0' ..= U+0037 '7'. + /// + /// # Examples + /// + /// ``` + /// #![feature(is_ascii_octdigit)] + /// + /// let uppercase_a = b'A'; + /// let a = b'a'; + /// let zero = b'0'; + /// let seven = b'7'; + /// let nine = b'9'; + /// let percent = b'%'; + /// let lf = b'\n'; + /// + /// assert!(!uppercase_a.is_ascii_octdigit()); + /// assert!(!a.is_ascii_octdigit()); + /// assert!(zero.is_ascii_octdigit()); + /// assert!(seven.is_ascii_octdigit()); + /// assert!(!nine.is_ascii_octdigit()); + /// assert!(!percent.is_ascii_octdigit()); + /// assert!(!lf.is_ascii_octdigit()); + /// ``` + #[must_use] + #[unstable(feature = "is_ascii_octdigit", issue = "101288")] + #[rustc_const_unstable(feature = "is_ascii_octdigit", issue = "101288")] + #[inline] + pub const fn is_ascii_octdigit(&self) -> bool { + matches!(*self, b'0'..=b'7') + } + /// Checks if the value is an ASCII hexadecimal digit: /// /// - U+0030 '0' ..= U+0039 '9', or diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 6d2cf3e83bce9..f5f2dd0477885 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -251,6 +251,23 @@ fn test_is_ascii_digit() { ); } +#[test] +fn test_is_ascii_octdigit() { + assert_all!(is_ascii_octdigit, "", "01234567"); + assert_none!( + is_ascii_octdigit, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + #[test] fn test_is_ascii_hexdigit() { assert_all!(is_ascii_hexdigit, "", "0123456789", "abcdefABCDEF",); @@ -454,6 +471,7 @@ fn ascii_ctype_const() { is_ascii_lowercase => [true, false, false, false, false]; is_ascii_alphanumeric => [true, true, true, false, false]; is_ascii_digit => [false, false, true, false, false]; + is_ascii_octdigit => [false, false, false, false, false]; is_ascii_hexdigit => [true, true, true, false, false]; is_ascii_punctuation => [false, false, false, true, false]; is_ascii_graphic => [true, true, true, true, false]; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 46f603eaebaca..46538ddb20179 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -101,6 +101,7 @@ #![feature(slice_flatten)] #![feature(provide_any)] #![feature(utf8_chunks)] +#![feature(is_ascii_octdigit)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; From 5fd02400e079d80f06170804bae8dfac1f58b6d1 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 13 Jun 2022 19:18:43 +0400 Subject: [PATCH 16/20] Add `Option::owned` --- library/alloc/src/lib.rs | 1 + library/alloc/src/option.rs | 575 ++++++++++++++++++++++++++++++++++++ library/core/src/option.rs | 1 + library/std/src/lib.rs | 4 +- 4 files changed, 579 insertions(+), 2 deletions(-) create mode 100644 library/alloc/src/option.rs diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7fde8f670a231..bbee87a2648d2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -230,6 +230,7 @@ pub mod collections; #[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))] pub mod ffi; pub mod fmt; +pub mod option; #[cfg(not(no_rc))] pub mod rc; pub mod slice; diff --git a/library/alloc/src/option.rs b/library/alloc/src/option.rs new file mode 100644 index 0000000000000..f798ef3c7f8ad --- /dev/null +++ b/library/alloc/src/option.rs @@ -0,0 +1,575 @@ +//! Optional values. +//! +//! Type [`Option`] represents an optional value: every [`Option`] +//! is either [`Some`] and contains a value, or [`None`], and +//! does not. [`Option`] types are very common in Rust code, as +//! they have a number of uses: +//! +//! * Initial values +//! * Return values for functions that are not defined +//! over their entire input range (partial functions) +//! * Return value for otherwise reporting simple errors, where [`None`] is +//! returned on error +//! * Optional struct fields +//! * Struct fields that can be loaned or "taken" +//! * Optional function arguments +//! * Nullable pointers +//! * Swapping things out of difficult situations +//! +//! [`Option`]s are commonly paired with pattern matching to query the presence +//! of a value and take action, always accounting for the [`None`] case. +//! +//! ``` +//! fn divide(numerator: f64, denominator: f64) -> Option { +//! if denominator == 0.0 { +//! None +//! } else { +//! Some(numerator / denominator) +//! } +//! } +//! +//! // The return value of the function is an option +//! let result = divide(2.0, 3.0); +//! +//! // Pattern match to retrieve the value +//! match result { +//! // The division was valid +//! Some(x) => println!("Result: {x}"), +//! // The division was invalid +//! None => println!("Cannot divide by 0"), +//! } +//! ``` +//! +// +// FIXME: Show how `Option` is used in practice, with lots of methods +// +//! # Options and pointers ("nullable" pointers) +//! +//! Rust's pointer types must always point to a valid location; there are +//! no "null" references. Instead, Rust has *optional* pointers, like +//! the optional owned box, [Option]<[Box\]>. +//! +//! [Box\]: ../../std/boxed/struct.Box.html +//! +//! The following example uses [`Option`] to create an optional box of +//! [`i32`]. Notice that in order to use the inner [`i32`] value, the +//! `check_optional` function first needs to use pattern matching to +//! determine whether the box has a value (i.e., it is [`Some(...)`][`Some`]) or +//! not ([`None`]). +//! +//! ``` +//! let optional = None; +//! check_optional(optional); +//! +//! let optional = Some(Box::new(9000)); +//! check_optional(optional); +//! +//! fn check_optional(optional: Option>) { +//! match optional { +//! Some(p) => println!("has value {p}"), +//! None => println!("has no value"), +//! } +//! } +//! ``` +//! +//! # Representation +//! +//! Rust guarantees to optimize the following types `T` such that +//! [`Option`] has the same size as `T`: +//! +//! * [`Box`] +//! * `&U` +//! * `&mut U` +//! * `fn`, `extern "C" fn`[^extern_fn] +//! * [`num::NonZero*`] +//! * [`ptr::NonNull`] +//! * `#[repr(transparent)]` struct around one of the types in this list. +//! +//! [^extern_fn]: this remains true for any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`) +//! +//! [`Box`]: ../../std/boxed/struct.Box.html +//! [`num::NonZero*`]: crate::num +//! [`ptr::NonNull`]: crate::ptr::NonNull +//! +//! This is called the "null pointer optimization" or NPO. +//! +//! It is further guaranteed that, for the cases above, one can +//! [`mem::transmute`] from all valid values of `T` to `Option` and +//! from `Some::(_)` to `T` (but transmuting `None::` to `T` +//! is undefined behaviour). +//! +//! # Method overview +//! +//! In addition to working with pattern matching, [`Option`] provides a wide +//! variety of different methods. +//! +//! ## Querying the variant +//! +//! The [`is_some`] and [`is_none`] methods return [`true`] if the [`Option`] +//! is [`Some`] or [`None`], respectively. +//! +//! [`is_none`]: Option::is_none +//! [`is_some`]: Option::is_some +//! +//! ## Adapters for working with references +//! +//! * [`as_ref`] converts from [&][][Option]\ to [Option]<[&]T> +//! * [`as_mut`] converts from [&mut] [Option]\ to [Option]<[&mut] T> +//! * [`as_deref`] converts from [&][][Option]\ to +//! [Option]<[&]T::[Target]> +//! * [`as_deref_mut`] converts from [&mut] [Option]\ to +//! [Option]<[&mut] T::[Target]> +//! * [`as_pin_ref`] converts from [Pin]<[&][][Option]\> to +//! [Option]<[Pin]<[&]T>> +//! * [`as_pin_mut`] converts from [Pin]<[&mut] [Option]\> to +//! [Option]<[Pin]<[&mut] T>> +//! +//! [&]: reference "shared reference" +//! [&mut]: reference "mutable reference" +//! [Target]: Deref::Target "ops::Deref::Target" +//! [`as_deref`]: Option::as_deref +//! [`as_deref_mut`]: Option::as_deref_mut +//! [`as_mut`]: Option::as_mut +//! [`as_pin_mut`]: Option::as_pin_mut +//! [`as_pin_ref`]: Option::as_pin_ref +//! [`as_ref`]: Option::as_ref +//! +//! ## Extracting the contained value +//! +//! These methods extract the contained value in an [`Option`] when it +//! is the [`Some`] variant. If the [`Option`] is [`None`]: +//! +//! * [`expect`] panics with a provided custom message +//! * [`unwrap`] panics with a generic message +//! * [`unwrap_or`] returns the provided default value +//! * [`unwrap_or_default`] returns the default value of the type `T` +//! (which must implement the [`Default`] trait) +//! * [`unwrap_or_else`] returns the result of evaluating the provided +//! function +//! +//! [`expect`]: Option::expect +//! [`unwrap`]: Option::unwrap +//! [`unwrap_or`]: Option::unwrap_or +//! [`unwrap_or_default`]: Option::unwrap_or_default +//! [`unwrap_or_else`]: Option::unwrap_or_else +//! +//! ## Transforming contained values +//! +//! These methods transform [`Option`] to [`Result`]: +//! +//! * [`ok_or`] transforms [`Some(v)`] to [`Ok(v)`], and [`None`] to +//! [`Err(err)`] using the provided default `err` value +//! * [`ok_or_else`] transforms [`Some(v)`] to [`Ok(v)`], and [`None`] to +//! a value of [`Err`] using the provided function +//! * [`transpose`] transposes an [`Option`] of a [`Result`] into a +//! [`Result`] of an [`Option`] +//! +//! [`Err(err)`]: Err +//! [`Ok(v)`]: Ok +//! [`Some(v)`]: Some +//! [`ok_or`]: Option::ok_or +//! [`ok_or_else`]: Option::ok_or_else +//! [`transpose`]: Option::transpose +//! +//! These methods transform the [`Some`] variant: +//! +//! * [`filter`] calls the provided predicate function on the contained +//! value `t` if the [`Option`] is [`Some(t)`], and returns [`Some(t)`] +//! if the function returns `true`; otherwise, returns [`None`] +//! * [`flatten`] removes one level of nesting from an +//! [`Option>`] +//! * [`map`] transforms [`Option`] to [`Option`] by applying the +//! provided function to the contained value of [`Some`] and leaving +//! [`None`] values unchanged +//! +//! [`Some(t)`]: Some +//! [`filter`]: Option::filter +//! [`flatten`]: Option::flatten +//! [`map`]: Option::map +//! +//! These methods transform [`Option`] to a value of a possibly +//! different type `U`: +//! +//! * [`map_or`] applies the provided function to the contained value of +//! [`Some`], or returns the provided default value if the [`Option`] is +//! [`None`] +//! * [`map_or_else`] applies the provided function to the contained value +//! of [`Some`], or returns the result of evaluating the provided +//! fallback function if the [`Option`] is [`None`] +//! +//! [`map_or`]: Option::map_or +//! [`map_or_else`]: Option::map_or_else +//! +//! These methods combine the [`Some`] variants of two [`Option`] values: +//! +//! * [`zip`] returns [`Some((s, o))`] if `self` is [`Some(s)`] and the +//! provided [`Option`] value is [`Some(o)`]; otherwise, returns [`None`] +//! * [`zip_with`] calls the provided function `f` and returns +//! [`Some(f(s, o))`] if `self` is [`Some(s)`] and the provided +//! [`Option`] value is [`Some(o)`]; otherwise, returns [`None`] +//! +//! [`Some(f(s, o))`]: Some +//! [`Some(o)`]: Some +//! [`Some(s)`]: Some +//! [`Some((s, o))`]: Some +//! [`zip`]: Option::zip +//! [`zip_with`]: Option::zip_with +//! +//! ## Boolean operators +//! +//! These methods treat the [`Option`] as a boolean value, where [`Some`] +//! acts like [`true`] and [`None`] acts like [`false`]. There are two +//! categories of these methods: ones that take an [`Option`] as input, and +//! ones that take a function as input (to be lazily evaluated). +//! +//! The [`and`], [`or`], and [`xor`] methods take another [`Option`] as +//! input, and produce an [`Option`] as output. Only the [`and`] method can +//! produce an [`Option`] value having a different inner type `U` than +//! [`Option`]. +//! +//! | method | self | input | output | +//! |---------|-----------|-----------|-----------| +//! | [`and`] | `None` | (ignored) | `None` | +//! | [`and`] | `Some(x)` | `None` | `None` | +//! | [`and`] | `Some(x)` | `Some(y)` | `Some(y)` | +//! | [`or`] | `None` | `None` | `None` | +//! | [`or`] | `None` | `Some(y)` | `Some(y)` | +//! | [`or`] | `Some(x)` | (ignored) | `Some(x)` | +//! | [`xor`] | `None` | `None` | `None` | +//! | [`xor`] | `None` | `Some(y)` | `Some(y)` | +//! | [`xor`] | `Some(x)` | `None` | `Some(x)` | +//! | [`xor`] | `Some(x)` | `Some(y)` | `None` | +//! +//! [`and`]: Option::and +//! [`or`]: Option::or +//! [`xor`]: Option::xor +//! +//! The [`and_then`] and [`or_else`] methods take a function as input, and +//! only evaluate the function when they need to produce a new value. Only +//! the [`and_then`] method can produce an [`Option`] value having a +//! different inner type `U` than [`Option`]. +//! +//! | method | self | function input | function result | output | +//! |--------------|-----------|----------------|-----------------|-----------| +//! | [`and_then`] | `None` | (not provided) | (not evaluated) | `None` | +//! | [`and_then`] | `Some(x)` | `x` | `None` | `None` | +//! | [`and_then`] | `Some(x)` | `x` | `Some(y)` | `Some(y)` | +//! | [`or_else`] | `None` | (not provided) | `None` | `None` | +//! | [`or_else`] | `None` | (not provided) | `Some(y)` | `Some(y)` | +//! | [`or_else`] | `Some(x)` | (not provided) | (not evaluated) | `Some(x)` | +//! +//! [`and_then`]: Option::and_then +//! [`or_else`]: Option::or_else +//! +//! This is an example of using methods like [`and_then`] and [`or`] in a +//! pipeline of method calls. Early stages of the pipeline pass failure +//! values ([`None`]) through unchanged, and continue processing on +//! success values ([`Some`]). Toward the end, [`or`] substitutes an error +//! message if it receives [`None`]. +//! +//! ``` +//! # use std::collections::BTreeMap; +//! let mut bt = BTreeMap::new(); +//! bt.insert(20u8, "foo"); +//! bt.insert(42u8, "bar"); +//! let res = [0u8, 1, 11, 200, 22] +//! .into_iter() +//! .map(|x| { +//! // `checked_sub()` returns `None` on error +//! x.checked_sub(1) +//! // same with `checked_mul()` +//! .and_then(|x| x.checked_mul(2)) +//! // `BTreeMap::get` returns `None` on error +//! .and_then(|x| bt.get(&x)) +//! // Substitute an error message if we have `None` so far +//! .or(Some(&"error!")) +//! .copied() +//! // Won't panic because we unconditionally used `Some` above +//! .unwrap() +//! }) +//! .collect::>(); +//! assert_eq!(res, ["error!", "error!", "foo", "error!", "bar"]); +//! ``` +//! +//! ## Comparison operators +//! +//! If `T` implements [`PartialOrd`] then [`Option`] will derive its +//! [`PartialOrd`] implementation. With this order, [`None`] compares as +//! less than any [`Some`], and two [`Some`] compare the same way as their +//! contained values would in `T`. If `T` also implements +//! [`Ord`], then so does [`Option`]. +//! +//! ``` +//! assert!(None < Some(0)); +//! assert!(Some(0) < Some(1)); +//! ``` +//! +//! ## Iterating over `Option` +//! +//! An [`Option`] can be iterated over. This can be helpful if you need an +//! iterator that is conditionally empty. The iterator will either produce +//! a single value (when the [`Option`] is [`Some`]), or produce no values +//! (when the [`Option`] is [`None`]). For example, [`into_iter`] acts like +//! [`once(v)`] if the [`Option`] is [`Some(v)`], and like [`empty()`] if +//! the [`Option`] is [`None`]. +//! +//! [`Some(v)`]: Some +//! [`empty()`]: crate::iter::empty +//! [`once(v)`]: crate::iter::once +//! +//! Iterators over [`Option`] come in three types: +//! +//! * [`into_iter`] consumes the [`Option`] and produces the contained +//! value +//! * [`iter`] produces an immutable reference of type `&T` to the +//! contained value +//! * [`iter_mut`] produces a mutable reference of type `&mut T` to the +//! contained value +//! +//! [`into_iter`]: Option::into_iter +//! [`iter`]: Option::iter +//! [`iter_mut`]: Option::iter_mut +//! +//! An iterator over [`Option`] can be useful when chaining iterators, for +//! example, to conditionally insert items. (It's not always necessary to +//! explicitly call an iterator constructor: many [`Iterator`] methods that +//! accept other iterators will also accept iterable types that implement +//! [`IntoIterator`], which includes [`Option`].) +//! +//! ``` +//! let yep = Some(42); +//! let nope = None; +//! // chain() already calls into_iter(), so we don't have to do so +//! let nums: Vec = (0..4).chain(yep).chain(4..8).collect(); +//! assert_eq!(nums, [0, 1, 2, 3, 42, 4, 5, 6, 7]); +//! let nums: Vec = (0..4).chain(nope).chain(4..8).collect(); +//! assert_eq!(nums, [0, 1, 2, 3, 4, 5, 6, 7]); +//! ``` +//! +//! One reason to chain iterators in this way is that a function returning +//! `impl Iterator` must have all possible return values be of the same +//! concrete type. Chaining an iterated [`Option`] can help with that. +//! +//! ``` +//! fn make_iter(do_insert: bool) -> impl Iterator { +//! // Explicit returns to illustrate return types matching +//! match do_insert { +//! true => return (0..4).chain(Some(42)).chain(4..8), +//! false => return (0..4).chain(None).chain(4..8), +//! } +//! } +//! println!("{:?}", make_iter(true).collect::>()); +//! println!("{:?}", make_iter(false).collect::>()); +//! ``` +//! +//! If we try to do the same thing, but using [`once()`] and [`empty()`], +//! we can't return `impl Iterator` anymore because the concrete types of +//! the return values differ. +//! +//! [`empty()`]: crate::iter::empty +//! [`once()`]: crate::iter::once +//! +//! ```compile_fail,E0308 +//! # use std::iter::{empty, once}; +//! // This won't compile because all possible returns from the function +//! // must have the same concrete type. +//! fn make_iter(do_insert: bool) -> impl Iterator { +//! // Explicit returns to illustrate return types not matching +//! match do_insert { +//! true => return (0..4).chain(once(42)).chain(4..8), +//! false => return (0..4).chain(empty()).chain(4..8), +//! } +//! } +//! ``` +//! +//! ## Collecting into `Option` +//! +//! [`Option`] implements the [`FromIterator`][impl-FromIterator] trait, +//! which allows an iterator over [`Option`] values to be collected into an +//! [`Option`] of a collection of each contained value of the original +//! [`Option`] values, or [`None`] if any of the elements was [`None`]. +//! +//! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E +//! +//! ``` +//! let v = [Some(2), Some(4), None, Some(8)]; +//! let res: Option> = v.into_iter().collect(); +//! assert_eq!(res, None); +//! let v = [Some(2), Some(4), Some(8)]; +//! let res: Option> = v.into_iter().collect(); +//! assert_eq!(res, Some(vec![2, 4, 8])); +//! ``` +//! +//! [`Option`] also implements the [`Product`][impl-Product] and +//! [`Sum`][impl-Sum] traits, allowing an iterator over [`Option`] values +//! to provide the [`product`][Iterator::product] and +//! [`sum`][Iterator::sum] methods. +//! +//! [impl-Product]: Option#impl-Product%3COption%3CU%3E%3E +//! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E +//! +//! ``` +//! let v = [None, Some(1), Some(2), Some(3)]; +//! let res: Option = v.into_iter().sum(); +//! assert_eq!(res, None); +//! let v = [Some(1), Some(2), Some(21)]; +//! let res: Option = v.into_iter().product(); +//! assert_eq!(res, Some(42)); +//! ``` +//! +//! ## Modifying an [`Option`] in-place +//! +//! These methods return a mutable reference to the contained value of an +//! [`Option`]: +//! +//! * [`insert`] inserts a value, dropping any old contents +//! * [`get_or_insert`] gets the current value, inserting a provided +//! default value if it is [`None`] +//! * [`get_or_insert_default`] gets the current value, inserting the +//! default value of type `T` (which must implement [`Default`]) if it is +//! [`None`] +//! * [`get_or_insert_with`] gets the current value, inserting a default +//! computed by the provided function if it is [`None`] +//! +//! [`get_or_insert`]: Option::get_or_insert +//! [`get_or_insert_default`]: Option::get_or_insert_default +//! [`get_or_insert_with`]: Option::get_or_insert_with +//! [`insert`]: Option::insert +//! +//! These methods transfer ownership of the contained value of an +//! [`Option`]: +//! +//! * [`take`] takes ownership of the contained value of an [`Option`], if +//! any, replacing the [`Option`] with [`None`] +//! * [`replace`] takes ownership of the contained value of an [`Option`], +//! if any, replacing the [`Option`] with a [`Some`] containing the +//! provided value +//! +//! [`replace`]: Option::replace +//! [`take`]: Option::take +//! +//! # Examples +//! +//! Basic pattern matching on [`Option`]: +//! +//! ``` +//! let msg = Some("howdy"); +//! +//! // Take a reference to the contained string +//! if let Some(m) = &msg { +//! println!("{}", *m); +//! } +//! +//! // Remove the contained string, destroying the Option +//! let unwrapped_msg = msg.unwrap_or("default message"); +//! ``` +//! +//! Initialize a result to [`None`] before a loop: +//! +//! ``` +//! enum Kingdom { Plant(u32, &'static str), Animal(u32, &'static str) } +//! +//! // A list of data to search through. +//! let all_the_big_things = [ +//! Kingdom::Plant(250, "redwood"), +//! Kingdom::Plant(230, "noble fir"), +//! Kingdom::Plant(229, "sugar pine"), +//! Kingdom::Animal(25, "blue whale"), +//! Kingdom::Animal(19, "fin whale"), +//! Kingdom::Animal(15, "north pacific right whale"), +//! ]; +//! +//! // We're going to search for the name of the biggest animal, +//! // but to start with we've just got `None`. +//! let mut name_of_biggest_animal = None; +//! let mut size_of_biggest_animal = 0; +//! for big_thing in &all_the_big_things { +//! match *big_thing { +//! Kingdom::Animal(size, name) if size > size_of_biggest_animal => { +//! // Now we've found the name of some big animal +//! size_of_biggest_animal = size; +//! name_of_biggest_animal = Some(name); +//! } +//! Kingdom::Animal(..) | Kingdom::Plant(..) => () +//! } +//! } +//! +//! match name_of_biggest_animal { +//! Some(name) => println!("the biggest animal is {name}"), +//! None => println!("there are no animals :("), +//! } +//! ``` +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::option::{IntoIter, Iter, IterMut, Option}; + +use crate::borrow::ToOwned; + +impl Option<&T> { + /// Maps an `Option<&T>` to an `Option` by cloning the contents of the + /// option. + /// + /// In difference with [`cloned`], this method uses [`ToOwned`] trait, which allows + /// to convert borrowed types to their owned variants. For example `Option<&[T]>` to + /// `Option>` + /// + /// [`cloned`]: Option::cloned + /// + /// # Examples + /// + /// ``` + /// let s = "string"; + /// let opt_s: Option<&str> = Some(x); + /// assert_eq!(opt_s, Some("string")); + /// let owned: Option = opt_s.owned(); + /// assert_eq!(owned, Some(String::from("string"))); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "`self` will be dropped if the result is not used"] + #[unstable(feature = "option_owned", issue = "none")] + #[rustc_const_unstable(feature = "const_option_owned", issue = "none")] + pub const fn owned(self) -> Option + where + T: ~const ToOwned, + { + match self { + Some(x) => Some(x.to_owned()), + None => None, + } + } +} + +impl Option<&mut T> { + /// Maps an `Option<&mut T>` to an `Option` by cloning the contents of the + /// option. + /// + /// In difference with [`cloned`], this method uses [`ToOwned`] trait, which allows + /// to convert borrowed types to their owned variants. For example `Option<&[T]>` to + /// `Option>` + /// + /// [`cloned`]: Option::cloned + /// + /// # Examples + /// + /// ``` + /// let s = "string"; + /// let opt_s: Option<&str> = Some(x); + /// assert_eq!(opt_s, Some("string")); + /// let owned: Option = opt_s.owned(); + /// assert_eq!(owned, Some(String::from("string"))); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "`self` will be dropped if the result is not used"] + #[unstable(feature = "option_owned", issue = "none")] + #[rustc_const_unstable(feature = "const_option_owned", issue = "none")] + pub const fn owned(self) -> Option + where + T: ~const ToOwned, + { + match self { + Some(x) => Some(x.to_owned()), + None => None, + } + } +} diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 4a93df4591b7a..70b7fac9380aa 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -515,6 +515,7 @@ use crate::{ #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[rustc_diagnostic_item = "Option"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_has_incoherent_inherent_impls] pub enum Option { /// No value. #[lang = "None"] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 97eed8a65c52e..9712d388ffe33 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -418,6 +418,8 @@ pub use alloc_crate::fmt; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::format; #[stable(feature = "rust1", since = "1.0.0")] +pub use alloc_crate::option; +#[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::rc; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::slice; @@ -479,8 +481,6 @@ pub use core::marker; pub use core::mem; #[stable(feature = "rust1", since = "1.0.0")] pub use core::ops; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::option; #[stable(feature = "pin", since = "1.33.0")] pub use core::pin; #[stable(feature = "rust1", since = "1.0.0")] From 90b57843b9b168cd6fc6aefd48da16c2191410b0 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 16 Jun 2022 13:10:16 +0400 Subject: [PATCH 17/20] Fix documentation links --- library/alloc/src/option.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/option.rs b/library/alloc/src/option.rs index f798ef3c7f8ad..abc6cb21f1cbe 100644 --- a/library/alloc/src/option.rs +++ b/library/alloc/src/option.rs @@ -88,8 +88,8 @@ //! [^extern_fn]: this remains true for any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`) //! //! [`Box`]: ../../std/boxed/struct.Box.html -//! [`num::NonZero*`]: crate::num -//! [`ptr::NonNull`]: crate::ptr::NonNull +//! [`num::NonZero*`]: core::num +//! [`ptr::NonNull`]: core::ptr::NonNull //! //! This is called the "null pointer optimization" or NPO. //! @@ -98,6 +98,8 @@ //! from `Some::(_)` to `T` (but transmuting `None::` to `T` //! is undefined behaviour). //! +//! [`mem::transmute`]: core::mem::transmute +//! //! # Method overview //! //! In addition to working with pattern matching, [`Option`] provides a wide @@ -126,13 +128,14 @@ //! //! [&]: reference "shared reference" //! [&mut]: reference "mutable reference" -//! [Target]: Deref::Target "ops::Deref::Target" +//! [Target]: core::ops::Deref::Target "ops::Deref::Target" //! [`as_deref`]: Option::as_deref //! [`as_deref_mut`]: Option::as_deref_mut //! [`as_mut`]: Option::as_mut //! [`as_pin_mut`]: Option::as_pin_mut //! [`as_pin_ref`]: Option::as_pin_ref //! [`as_ref`]: Option::as_ref +//! [Pin]: core::pin::Pin //! //! ## Extracting the contained value //! @@ -314,8 +317,8 @@ //! the [`Option`] is [`None`]. //! //! [`Some(v)`]: Some -//! [`empty()`]: crate::iter::empty -//! [`once(v)`]: crate::iter::once +//! [`empty()`]: core::iter::empty +//! [`once(v)`]: core::iter::once //! //! Iterators over [`Option`] come in three types: //! @@ -366,8 +369,8 @@ //! we can't return `impl Iterator` anymore because the concrete types of //! the return values differ. //! -//! [`empty()`]: crate::iter::empty -//! [`once()`]: crate::iter::once +//! [`empty()`]: core::iter::empty +//! [`once()`]: core::iter::once //! //! ```compile_fail,E0308 //! # use std::iter::{empty, once}; From e962dd96338268ca44ebdcd22281931a11ac7937 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 16 Jun 2022 14:36:48 +0400 Subject: [PATCH 18/20] fix doctests --- library/alloc/src/option.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/option.rs b/library/alloc/src/option.rs index abc6cb21f1cbe..893887b484562 100644 --- a/library/alloc/src/option.rs +++ b/library/alloc/src/option.rs @@ -522,8 +522,10 @@ impl Option<&T> { /// # Examples /// /// ``` + /// #![feature(option_owned)] + /// /// let s = "string"; - /// let opt_s: Option<&str> = Some(x); + /// let opt_s: Option<&str> = Some(s); /// assert_eq!(opt_s, Some("string")); /// let owned: Option = opt_s.owned(); /// assert_eq!(owned, Some(String::from("string"))); @@ -556,8 +558,10 @@ impl Option<&mut T> { /// # Examples /// /// ``` + /// #![feature(option_owned)] + /// /// let s = "string"; - /// let opt_s: Option<&str> = Some(x); + /// let opt_s: Option<&str> = Some(s); /// assert_eq!(opt_s, Some("string")); /// let owned: Option = opt_s.owned(); /// assert_eq!(owned, Some(String::from("string"))); From 2a6f61c776d260ea89c7be672546ed4e9c679516 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 17 Jun 2022 19:40:24 +0400 Subject: [PATCH 19/20] Add `Result::owned` --- library/alloc/src/lib.rs | 1 + library/alloc/src/result.rs | 565 ++++++++++++++++++++++++++++++++++++ library/core/src/result.rs | 1 + library/std/src/lib.rs | 4 +- 4 files changed, 569 insertions(+), 2 deletions(-) create mode 100644 library/alloc/src/result.rs diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index bbee87a2648d2..27982907a2980 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -233,6 +233,7 @@ pub mod fmt; pub mod option; #[cfg(not(no_rc))] pub mod rc; +pub mod result; pub mod slice; pub mod str; pub mod string; diff --git a/library/alloc/src/result.rs b/library/alloc/src/result.rs new file mode 100644 index 0000000000000..394f220772a5c --- /dev/null +++ b/library/alloc/src/result.rs @@ -0,0 +1,565 @@ +//! Error handling with the `Result` type. +//! +//! [`Result`][`Result`] is the type used for returning and propagating +//! errors. It is an enum with the variants, [`Ok(T)`], representing +//! success and containing a value, and [`Err(E)`], representing error +//! and containing an error value. +//! +//! ``` +//! # #[allow(dead_code)] +//! enum Result { +//! Ok(T), +//! Err(E), +//! } +//! ``` +//! +//! Functions return [`Result`] whenever errors are expected and +//! recoverable. In the `std` crate, [`Result`] is most prominently used +//! for [I/O](../../std/io/index.html). +//! +//! A simple function returning [`Result`] might be +//! defined and used like so: +//! +//! ``` +//! #[derive(Debug)] +//! enum Version { Version1, Version2 } +//! +//! fn parse_version(header: &[u8]) -> Result { +//! match header.get(0) { +//! None => Err("invalid header length"), +//! Some(&1) => Ok(Version::Version1), +//! Some(&2) => Ok(Version::Version2), +//! Some(_) => Err("invalid version"), +//! } +//! } +//! +//! let version = parse_version(&[1, 2, 3, 4]); +//! match version { +//! Ok(v) => println!("working with version: {v:?}"), +//! Err(e) => println!("error parsing header: {e:?}"), +//! } +//! ``` +//! +//! Pattern matching on [`Result`]s is clear and straightforward for +//! simple cases, but [`Result`] comes with some convenience methods +//! that make working with it more succinct. +//! +//! ``` +//! let good_result: Result = Ok(10); +//! let bad_result: Result = Err(10); +//! +//! // The `is_ok` and `is_err` methods do what they say. +//! assert!(good_result.is_ok() && !good_result.is_err()); +//! assert!(bad_result.is_err() && !bad_result.is_ok()); +//! +//! // `map` consumes the `Result` and produces another. +//! let good_result: Result = good_result.map(|i| i + 1); +//! let bad_result: Result = bad_result.map(|i| i - 1); +//! +//! // Use `and_then` to continue the computation. +//! let good_result: Result = good_result.and_then(|i| Ok(i == 11)); +//! +//! // Use `or_else` to handle the error. +//! let bad_result: Result = bad_result.or_else(|i| Ok(i + 20)); +//! +//! // Consume the result and return the contents with `unwrap`. +//! let final_awesome_result = good_result.unwrap(); +//! ``` +//! +//! # Results must be used +//! +//! A common problem with using return values to indicate errors is +//! that it is easy to ignore the return value, thus failing to handle +//! the error. [`Result`] is annotated with the `#[must_use]` attribute, +//! which will cause the compiler to issue a warning when a Result +//! value is ignored. This makes [`Result`] especially useful with +//! functions that may encounter errors but don't otherwise return a +//! useful value. +//! +//! Consider the [`write_all`] method defined for I/O types +//! by the [`Write`] trait: +//! +//! ``` +//! use std::io; +//! +//! trait Write { +//! fn write_all(&mut self, bytes: &[u8]) -> Result<(), io::Error>; +//! } +//! ``` +//! +//! *Note: The actual definition of [`Write`] uses [`io::Result`], which +//! is just a synonym for [Result].* +//! +//! This method doesn't produce a value, but the write may +//! fail. It's crucial to handle the error case, and *not* write +//! something like this: +//! +//! ```no_run +//! # #![allow(unused_must_use)] // \o/ +//! use std::fs::File; +//! use std::io::prelude::*; +//! +//! let mut file = File::create("valuable_data.txt").unwrap(); +//! // If `write_all` errors, then we'll never know, because the return +//! // value is ignored. +//! file.write_all(b"important message"); +//! ``` +//! +//! If you *do* write that in Rust, the compiler will give you a +//! warning (by default, controlled by the `unused_must_use` lint). +//! +//! You might instead, if you don't want to handle the error, simply +//! assert success with [`expect`]. This will panic if the +//! write fails, providing a marginally useful message indicating why: +//! +//! ```no_run +//! use std::fs::File; +//! use std::io::prelude::*; +//! +//! let mut file = File::create("valuable_data.txt").unwrap(); +//! file.write_all(b"important message").expect("failed to write message"); +//! ``` +//! +//! You might also simply assert success: +//! +//! ```no_run +//! # use std::fs::File; +//! # use std::io::prelude::*; +//! # let mut file = File::create("valuable_data.txt").unwrap(); +//! assert!(file.write_all(b"important message").is_ok()); +//! ``` +//! +//! Or propagate the error up the call stack with [`?`]: +//! +//! ``` +//! # use std::fs::File; +//! # use std::io::prelude::*; +//! # use std::io; +//! # #[allow(dead_code)] +//! fn write_message() -> io::Result<()> { +//! let mut file = File::create("valuable_data.txt")?; +//! file.write_all(b"important message")?; +//! Ok(()) +//! } +//! ``` +//! +//! # The question mark operator, `?` +//! +//! When writing code that calls many functions that return the +//! [`Result`] type, the error handling can be tedious. The question mark +//! operator, [`?`], hides some of the boilerplate of propagating errors +//! up the call stack. +//! +//! It replaces this: +//! +//! ``` +//! # #![allow(dead_code)] +//! use std::fs::File; +//! use std::io::prelude::*; +//! use std::io; +//! +//! struct Info { +//! name: String, +//! age: i32, +//! rating: i32, +//! } +//! +//! fn write_info(info: &Info) -> io::Result<()> { +//! // Early return on error +//! let mut file = match File::create("my_best_friends.txt") { +//! Err(e) => return Err(e), +//! Ok(f) => f, +//! }; +//! if let Err(e) = file.write_all(format!("name: {}\n", info.name).as_bytes()) { +//! return Err(e) +//! } +//! if let Err(e) = file.write_all(format!("age: {}\n", info.age).as_bytes()) { +//! return Err(e) +//! } +//! if let Err(e) = file.write_all(format!("rating: {}\n", info.rating).as_bytes()) { +//! return Err(e) +//! } +//! Ok(()) +//! } +//! ``` +//! +//! With this: +//! +//! ``` +//! # #![allow(dead_code)] +//! use std::fs::File; +//! use std::io::prelude::*; +//! use std::io; +//! +//! struct Info { +//! name: String, +//! age: i32, +//! rating: i32, +//! } +//! +//! fn write_info(info: &Info) -> io::Result<()> { +//! let mut file = File::create("my_best_friends.txt")?; +//! // Early return on error +//! file.write_all(format!("name: {}\n", info.name).as_bytes())?; +//! file.write_all(format!("age: {}\n", info.age).as_bytes())?; +//! file.write_all(format!("rating: {}\n", info.rating).as_bytes())?; +//! Ok(()) +//! } +//! ``` +//! +//! *It's much nicer!* +//! +//! Ending the expression with [`?`] will result in the unwrapped +//! success ([`Ok`]) value, unless the result is [`Err`], in which case +//! [`Err`] is returned early from the enclosing function. +//! +//! [`?`] can only be used in functions that return [`Result`] because of the +//! early return of [`Err`] that it provides. +//! +//! [`expect`]: Result::expect +//! [`Write`]: ../../std/io/trait.Write.html "io::Write" +//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all "io::Write::write_all" +//! [`io::Result`]: ../../std/io/type.Result.html "io::Result" +//! [`?`]: core::ops::Try +//! [`Ok(T)`]: Ok +//! [`Err(E)`]: Err +//! [io::Error]: ../../std/io/struct.Error.html "io::Error" +//! +//! # Method overview +//! +//! In addition to working with pattern matching, [`Result`] provides a +//! wide variety of different methods. +//! +//! ## Querying the variant +//! +//! The [`is_ok`] and [`is_err`] methods return [`true`] if the [`Result`] +//! is [`Ok`] or [`Err`], respectively. +//! +//! [`is_err`]: Result::is_err +//! [`is_ok`]: Result::is_ok +//! +//! ## Adapters for working with references +//! +//! * [`as_ref`] converts from `&Result` to `Result<&T, &E>` +//! * [`as_mut`] converts from `&mut Result` to `Result<&mut T, &mut E>` +//! * [`as_deref`] converts from `&Result` to `Result<&T::Target, &E>` +//! * [`as_deref_mut`] converts from `&mut Result` to +//! `Result<&mut T::Target, &mut E>` +//! +//! [`as_deref`]: Result::as_deref +//! [`as_deref_mut`]: Result::as_deref_mut +//! [`as_mut`]: Result::as_mut +//! [`as_ref`]: Result::as_ref +//! +//! ## Extracting contained values +//! +//! These methods extract the contained value in a [`Result`] when it +//! is the [`Ok`] variant. If the [`Result`] is [`Err`]: +//! +//! * [`expect`] panics with a provided custom message +//! * [`unwrap`] panics with a generic message +//! * [`unwrap_or`] returns the provided default value +//! * [`unwrap_or_default`] returns the default value of the type `T` +//! (which must implement the [`Default`] trait) +//! * [`unwrap_or_else`] returns the result of evaluating the provided +//! function +//! +//! The panicking methods [`expect`] and [`unwrap`] require `E` to +//! implement the [`Debug`] trait. +//! +//! [`Debug`]: crate::fmt::Debug +//! [`expect`]: Result::expect +//! [`unwrap`]: Result::unwrap +//! [`unwrap_or`]: Result::unwrap_or +//! [`unwrap_or_default`]: Result::unwrap_or_default +//! [`unwrap_or_else`]: Result::unwrap_or_else +//! +//! These methods extract the contained value in a [`Result`] when it +//! is the [`Err`] variant. They require `T` to implement the [`Debug`] +//! trait. If the [`Result`] is [`Ok`]: +//! +//! * [`expect_err`] panics with a provided custom message +//! * [`unwrap_err`] panics with a generic message +//! +//! [`Debug`]: core::fmt::Debug +//! [`expect_err`]: Result::expect_err +//! [`unwrap_err`]: Result::unwrap_err +//! +//! ## Transforming contained values +//! +//! These methods transform [`Result`] to [`Option`]: +//! +//! * [`err`][Result::err] transforms [`Result`] into [`Option`], +//! mapping [`Err(e)`] to [`Some(e)`] and [`Ok(v)`] to [`None`] +//! * [`ok`][Result::ok] transforms [`Result`] into [`Option`], +//! mapping [`Ok(v)`] to [`Some(v)`] and [`Err(e)`] to [`None`] +//! * [`transpose`] transposes a [`Result`] of an [`Option`] into an +//! [`Option`] of a [`Result`] +//! +// Do NOT add link reference definitions for `err` or `ok`, because they +// will generate numerous incorrect URLs for `Err` and `Ok` elsewhere, due +// to case folding. +//! +//! [`Err(e)`]: Err +//! [`Ok(v)`]: Ok +//! [`Some(e)`]: Option::Some +//! [`Some(v)`]: Option::Some +//! [`transpose`]: Result::transpose +//! +//! This method transforms the contained value of the [`Ok`] variant: +//! +//! * [`map`] transforms [`Result`] into [`Result`] by applying +//! the provided function to the contained value of [`Ok`] and leaving +//! [`Err`] values unchanged +//! +//! [`map`]: Result::map +//! +//! This method transforms the contained value of the [`Err`] variant: +//! +//! * [`map_err`] transforms [`Result`] into [`Result`] by +//! applying the provided function to the contained value of [`Err`] and +//! leaving [`Ok`] values unchanged +//! +//! [`map_err`]: Result::map_err +//! +//! These methods transform a [`Result`] into a value of a possibly +//! different type `U`: +//! +//! * [`map_or`] applies the provided function to the contained value of +//! [`Ok`], or returns the provided default value if the [`Result`] is +//! [`Err`] +//! * [`map_or_else`] applies the provided function to the contained value +//! of [`Ok`], or applies the provided default fallback function to the +//! contained value of [`Err`] +//! +//! [`map_or`]: Result::map_or +//! [`map_or_else`]: Result::map_or_else +//! +//! ## Boolean operators +//! +//! These methods treat the [`Result`] as a boolean value, where [`Ok`] +//! acts like [`true`] and [`Err`] acts like [`false`]. There are two +//! categories of these methods: ones that take a [`Result`] as input, and +//! ones that take a function as input (to be lazily evaluated). +//! +//! The [`and`] and [`or`] methods take another [`Result`] as input, and +//! produce a [`Result`] as output. The [`and`] method can produce a +//! [`Result`] value having a different inner type `U` than +//! [`Result`]. The [`or`] method can produce a [`Result`] +//! value having a different error type `F` than [`Result`]. +//! +//! | method | self | input | output | +//! |---------|----------|-----------|----------| +//! | [`and`] | `Err(e)` | (ignored) | `Err(e)` | +//! | [`and`] | `Ok(x)` | `Err(d)` | `Err(d)` | +//! | [`and`] | `Ok(x)` | `Ok(y)` | `Ok(y)` | +//! | [`or`] | `Err(e)` | `Err(d)` | `Err(d)` | +//! | [`or`] | `Err(e)` | `Ok(y)` | `Ok(y)` | +//! | [`or`] | `Ok(x)` | (ignored) | `Ok(x)` | +//! +//! [`and`]: Result::and +//! [`or`]: Result::or +//! +//! The [`and_then`] and [`or_else`] methods take a function as input, and +//! only evaluate the function when they need to produce a new value. The +//! [`and_then`] method can produce a [`Result`] value having a +//! different inner type `U` than [`Result`]. The [`or_else`] method +//! can produce a [`Result`] value having a different error type `F` +//! than [`Result`]. +//! +//! | method | self | function input | function result | output | +//! |--------------|----------|----------------|-----------------|----------| +//! | [`and_then`] | `Err(e)` | (not provided) | (not evaluated) | `Err(e)` | +//! | [`and_then`] | `Ok(x)` | `x` | `Err(d)` | `Err(d)` | +//! | [`and_then`] | `Ok(x)` | `x` | `Ok(y)` | `Ok(y)` | +//! | [`or_else`] | `Err(e)` | `e` | `Err(d)` | `Err(d)` | +//! | [`or_else`] | `Err(e)` | `e` | `Ok(y)` | `Ok(y)` | +//! | [`or_else`] | `Ok(x)` | (not provided) | (not evaluated) | `Ok(x)` | +//! +//! [`and_then`]: Result::and_then +//! [`or_else`]: Result::or_else +//! +//! ## Comparison operators +//! +//! If `T` and `E` both implement [`PartialOrd`] then [`Result`] will +//! derive its [`PartialOrd`] implementation. With this order, an [`Ok`] +//! compares as less than any [`Err`], while two [`Ok`] or two [`Err`] +//! compare as their contained values would in `T` or `E` respectively. If `T` +//! and `E` both also implement [`Ord`], then so does [`Result`]. +//! +//! ``` +//! assert!(Ok(1) < Err(0)); +//! let x: Result = Ok(0); +//! let y = Ok(1); +//! assert!(x < y); +//! let x: Result<(), i32> = Err(0); +//! let y = Err(1); +//! assert!(x < y); +//! ``` +//! +//! ## Iterating over `Result` +//! +//! A [`Result`] can be iterated over. This can be helpful if you need an +//! iterator that is conditionally empty. The iterator will either produce +//! a single value (when the [`Result`] is [`Ok`]), or produce no values +//! (when the [`Result`] is [`Err`]). For example, [`into_iter`] acts like +//! [`once(v)`] if the [`Result`] is [`Ok(v)`], and like [`empty()`] if the +//! [`Result`] is [`Err`]. +//! +//! [`Ok(v)`]: Ok +//! [`empty()`]: core::iter::empty +//! [`once(v)`]: core::iter::once +//! +//! Iterators over [`Result`] come in three types: +//! +//! * [`into_iter`] consumes the [`Result`] and produces the contained +//! value +//! * [`iter`] produces an immutable reference of type `&T` to the +//! contained value +//! * [`iter_mut`] produces a mutable reference of type `&mut T` to the +//! contained value +//! +//! See [Iterating over `Option`] for examples of how this can be useful. +//! +//! [Iterating over `Option`]: crate::option#iterating-over-option +//! [`into_iter`]: Result::into_iter +//! [`iter`]: Result::iter +//! [`iter_mut`]: Result::iter_mut +//! +//! You might want to use an iterator chain to do multiple instances of an +//! operation that can fail, but would like to ignore failures while +//! continuing to process the successful results. In this example, we take +//! advantage of the iterable nature of [`Result`] to select only the +//! [`Ok`] values using [`flatten`][Iterator::flatten]. +//! +//! ``` +//! # use std::str::FromStr; +//! let mut results = vec![]; +//! let mut errs = vec![]; +//! let nums: Vec<_> = ["17", "not a number", "99", "-27", "768"] +//! .into_iter() +//! .map(u8::from_str) +//! // Save clones of the raw `Result` values to inspect +//! .inspect(|x| results.push(x.clone())) +//! // Challenge: explain how this captures only the `Err` values +//! .inspect(|x| errs.extend(x.clone().err())) +//! .flatten() +//! .collect(); +//! assert_eq!(errs.len(), 3); +//! assert_eq!(nums, [17, 99]); +//! println!("results {results:?}"); +//! println!("errs {errs:?}"); +//! println!("nums {nums:?}"); +//! ``` +//! +//! ## Collecting into `Result` +//! +//! [`Result`] implements the [`FromIterator`][impl-FromIterator] trait, +//! which allows an iterator over [`Result`] values to be collected into a +//! [`Result`] of a collection of each contained value of the original +//! [`Result`] values, or [`Err`] if any of the elements was [`Err`]. +//! +//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E +//! +//! ``` +//! let v = [Ok(2), Ok(4), Err("err!"), Ok(8)]; +//! let res: Result, &str> = v.into_iter().collect(); +//! assert_eq!(res, Err("err!")); +//! let v = [Ok(2), Ok(4), Ok(8)]; +//! let res: Result, &str> = v.into_iter().collect(); +//! assert_eq!(res, Ok(vec![2, 4, 8])); +//! ``` +//! +//! [`Result`] also implements the [`Product`][impl-Product] and +//! [`Sum`][impl-Sum] traits, allowing an iterator over [`Result`] values +//! to provide the [`product`][Iterator::product] and +//! [`sum`][Iterator::sum] methods. +//! +//! [impl-Product]: Result#impl-Product%3CResult%3CU%2C%20E%3E%3E +//! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E +//! +//! ``` +//! let v = [Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")]; +//! let res: Result = v.into_iter().sum(); +//! assert_eq!(res, Err("error!")); +//! let v = [Ok(1), Ok(2), Ok(21)]; +//! let res: Result = v.into_iter().product(); +//! assert_eq!(res, Ok(42)); +//! ``` + +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::result::{IntoIter, Iter, IterMut, Result}; + +use crate::borrow::ToOwned; + +impl Result<&T, E> { + /// Maps an `Result<&T>` to an `Result` by cloning the contents of the + /// result. + /// + /// In difference with [`cloned`], this method uses [`ToOwned`] trait, which allows + /// to convert borrowed types to their owned variants. For example `Result<&[T], E>` to + /// `Result, E>` + /// + /// [`cloned`]: Result::cloned + /// + /// # Examples + /// + /// ``` + /// #![feature(result_owned)] + /// + /// let s = "string"; + /// let res_s: Result<&str, ()> = Ok(s); + /// assert_eq!(res_s, Ok("string")); + /// let owned: Result = res_s.owned(); + /// assert_eq!(owned, Ok(String::from("string"))); + /// ``` + #[rustc_allow_incoherent_impl] + #[unstable(feature = "result_owned", issue = "none")] + #[rustc_const_unstable(feature = "const_option_owned", issue = "none")] + pub const fn owned(self) -> Result + where + T: ~const ToOwned, + { + match self { + Ok(x) => Ok(x.to_owned()), + Err(e) => Err(e), + } + } +} + +impl Result<&mut T, E> { + /// Maps an `Result<&mut T>` to an `Result` by cloning the contents of the + /// result. + /// + /// In difference with [`cloned`], this method uses [`ToOwned`] trait, which allows + /// to convert borrowed types to their owned variants. For example `Result<&[T], E>` to + /// `Result, E>` + /// + /// [`cloned`]: Result::cloned + /// + /// # Examples + /// + /// ``` + /// #![feature(result_owned)] + /// + /// let s = "string"; + /// let res_s: Result<&str, ()> = Ok(s); + /// assert_eq!(res_s, Ok("string")); + /// let owned: Result = res_s.owned(); + /// assert_eq!(owned, Ok(String::from("string"))); + /// ``` + #[rustc_allow_incoherent_impl] + #[unstable(feature = "result_owned", issue = "none")] + #[rustc_const_unstable(feature = "const_option_owned", issue = "none")] + pub const fn owned(self) -> Result + where + T: ~const ToOwned, + { + match self { + Ok(x) => Ok(x.to_owned()), + Err(e) => Err(e), + } + } +} diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 41fcb14d42bec..622cf2aa3580f 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -501,6 +501,7 @@ use crate::{convert, fmt, hint}; #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[rustc_diagnostic_item = "Result"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_has_incoherent_inherent_impls] pub enum Result { /// Contains the success value #[lang = "Ok"] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 9712d388ffe33..3590298b5e13e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -422,6 +422,8 @@ pub use alloc_crate::option; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::rc; #[stable(feature = "rust1", since = "1.0.0")] +pub use alloc_crate::result; +#[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::slice; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::str; @@ -485,8 +487,6 @@ pub use core::ops; pub use core::pin; #[stable(feature = "rust1", since = "1.0.0")] pub use core::ptr; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::result; #[stable(feature = "i128", since = "1.26.0")] #[allow(deprecated, deprecated_in_future)] pub use core::u128; From b9c0467e0c87c38009087eea65a79994d6bf1f26 Mon Sep 17 00:00:00 2001 From: pierwill Date: Sun, 2 Oct 2022 16:02:57 -0500 Subject: [PATCH 20/20] Add diagnostic struct for const eval error in `rustc_middle` Co-authored-by: Michael Goulet --- compiler/rustc_error_messages/locales/en-US/middle.ftl | 3 +++ compiler/rustc_middle/src/error.rs | 7 +++++++ compiler/rustc_middle/src/ty/adt.rs | 8 +++----- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl index ed834886453ce..ca3c91ce24a1d 100644 --- a/compiler/rustc_error_messages/locales/en-US/middle.ftl +++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl @@ -15,3 +15,6 @@ middle_previous_use_here = middle_limit_invalid = `limit` must be a non-negative integer .label = {$error_str} + +middle_const_eval_non_int = + constant evaluation of enum discriminant resulted in non-integer diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index a4ceb494569b1..e69cb546d15f6 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -48,3 +48,10 @@ pub struct LimitInvalid<'a> { pub value_span: Span, pub error_str: &'a str, } + +#[derive(Diagnostic)] +#[diag(middle::const_eval_non_int)] +pub struct ConstEvalNonIntError { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 74ce0b38ed22a..3c485e2640970 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -458,11 +458,9 @@ impl<'tcx> AdtDef<'tcx> { Some(Discr { val: b, ty }) } else { info!("invalid enum discriminant: {:#?}", val); - crate::mir::interpret::struct_error( - tcx.at(tcx.def_span(expr_did)), - "constant evaluation of enum discriminant resulted in non-integer", - ) - .emit(); + tcx.sess.emit_err(crate::error::ConstEvalNonIntError { + span: tcx.def_span(expr_did), + }); None } }