diff options
Diffstat (limited to '')
-rw-r--r-- | library/core/src/array/equality.rs | 7 | ||||
-rw-r--r-- | library/core/src/array/iter.rs | 59 | ||||
-rw-r--r-- | library/core/src/array/mod.rs | 68 |
3 files changed, 94 insertions, 40 deletions
diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index 33f7f494e..b2c895f88 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -173,13 +173,14 @@ macro_rules! is_raw_eq_comparable { )+}; } -// SAFETY: All the ordinary integer types allow all bit patterns as distinct values +// SAFETY: All the ordinary integer types have no padding, and are not pointers. is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); -// SAFETY: bool and char have *niches*, but no *padding*, so this is sound +// SAFETY: bool and char have *niches*, but no *padding* (and these are not pointer types), so this +// is sound is_raw_eq_comparable!(bool, char); -// SAFETY: Similarly, the non-zero types have a niche, but no undef, +// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers, // and they compare like their underlying numeric type. is_raw_eq_comparable!( NonZeroU8, diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index f4885ed9f..b91c63018 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -1,10 +1,10 @@ //! Defines the `IntoIter` owned iterator for arrays. use crate::{ - cmp, fmt, + fmt, iter::{self, ExactSizeIterator, FusedIterator, TrustedLen}, mem::{self, MaybeUninit}, - ops::Range, + ops::{IndexRange, Range}, ptr, }; @@ -29,9 +29,10 @@ pub struct IntoIter<T, const N: usize> { /// The elements in `data` that have not been yielded yet. /// /// Invariants: - /// - `alive.start <= alive.end` /// - `alive.end <= N` - alive: Range<usize>, + /// + /// (And the `IndexRange` type requires `alive.start <= alive.end`.) + alive: IndexRange, } // Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator` @@ -69,7 +70,7 @@ impl<T, const N: usize> IntoIterator for [T; N] { // Until then, we can use `mem::transmute_copy` to create a bitwise copy // as a different type, then forget `array` so that it is not dropped. unsafe { - let iter = IntoIter { data: mem::transmute_copy(&self), alive: 0..N }; + let iter = IntoIter { data: mem::transmute_copy(&self), alive: IndexRange::zero_to(N) }; mem::forget(self); iter } @@ -103,8 +104,7 @@ impl<T, const N: usize> IntoIter<T, N> { /// /// ``` /// #![feature(array_into_iter_constructors)] - /// - /// #![feature(maybe_uninit_array_assume_init)] + /// #![feature(maybe_uninit_uninit_array_transpose)] /// #![feature(maybe_uninit_uninit_array)] /// use std::array::IntoIter; /// use std::mem::MaybeUninit; @@ -133,7 +133,7 @@ impl<T, const N: usize> IntoIter<T, N> { /// } /// /// // SAFETY: We've initialized all N items - /// unsafe { Ok(MaybeUninit::array_assume_init(buffer)) } + /// unsafe { Ok(buffer.transpose().assume_init()) } /// } /// /// let r: [_; 4] = next_chunk(&mut (10..16)).unwrap(); @@ -147,7 +147,9 @@ impl<T, const N: usize> IntoIter<T, N> { buffer: [MaybeUninit<T>; N], initialized: Range<usize>, ) -> Self { - Self { data: buffer, alive: initialized } + // SAFETY: one of our safety conditions is that the range is canonical. + let alive = unsafe { IndexRange::new_unchecked(initialized.start, initialized.end) }; + Self { data: buffer, alive } } /// Creates an iterator over `T` which returns no elements. @@ -283,16 +285,11 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> { } fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let len = self.len(); - - // The number of elements to drop. Always in-bounds by construction. - let delta = cmp::min(n, len); + let original_len = self.len(); - let range_to_drop = self.alive.start..(self.alive.start + delta); - - // Moving the start marks them as conceptually "dropped", so if anything - // goes bad then our drop impl won't double-free them. - self.alive.start += delta; + // This also moves the start, which marks them as conceptually "dropped", + // so if anything goes bad then our drop impl won't double-free them. + let range_to_drop = self.alive.take_prefix(n); // SAFETY: These elements are currently initialized, so it's fine to drop them. unsafe { @@ -300,7 +297,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> { ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); } - if n > len { Err(len) } else { Ok(()) } + if n > original_len { Err(original_len) } else { Ok(()) } } } @@ -338,16 +335,11 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> { } fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - let len = self.len(); - - // The number of elements to drop. Always in-bounds by construction. - let delta = cmp::min(n, len); - - let range_to_drop = (self.alive.end - delta)..self.alive.end; + let original_len = self.len(); - // Moving the end marks them as conceptually "dropped", so if anything - // goes bad then our drop impl won't double-free them. - self.alive.end -= delta; + // This also moves the end, which marks them as conceptually "dropped", + // so if anything goes bad then our drop impl won't double-free them. + let range_to_drop = self.alive.take_suffix(n); // SAFETY: These elements are currently initialized, so it's fine to drop them. unsafe { @@ -355,7 +347,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> { ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); } - if n > len { Err(len) } else { Ok(()) } + if n > original_len { Err(original_len) } else { Ok(()) } } } @@ -372,9 +364,7 @@ impl<T, const N: usize> Drop for IntoIter<T, N> { #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> { fn len(&self) -> usize { - // Will never underflow due to the invariant `alive.start <= - // alive.end`. - self.alive.end - self.alive.start + self.alive.len() } fn is_empty(&self) -> bool { self.alive.is_empty() @@ -396,14 +386,15 @@ impl<T: Clone, const N: usize> Clone for IntoIter<T, N> { fn clone(&self) -> Self { // Note, we don't really need to match the exact same alive range, so // we can just clone into offset 0 regardless of where `self` is. - let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 }; + let mut new = Self { data: MaybeUninit::uninit_array(), alive: IndexRange::zero_to(0) }; // Clone all alive elements. for (src, dst) in iter::zip(self.as_slice(), &mut new.data) { // Write a clone into the new array, then update its alive range. // If cloning panics, we'll correctly drop the previous items. dst.write(src.clone()); - new.alive.end += 1; + // This addition cannot overflow as we're iterating a slice + new.alive = IndexRange::zero_to(new.alive.end() + 1); } new diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index c9823a136..eae0e1c76 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -1,4 +1,4 @@ -//! Helper functions and types for fixed-length arrays. +//! Utilities for the array primitive type. //! //! *[See also the array primitive type](array).* @@ -7,6 +7,7 @@ use crate::borrow::{Borrow, BorrowMut}; use crate::cmp::Ordering; use crate::convert::{Infallible, TryFrom}; +use crate::error::Error; use crate::fmt; use crate::hash::{self, Hash}; use crate::iter::TrustedLen; @@ -31,6 +32,10 @@ pub use iter::IntoIter; /// # Example /// /// ```rust +/// // type inference is helping us here, the way `from_fn` knows how many +/// // elements to produce is the length of array down there: only arrays of +/// // equal lengths can be compared, so the const generic parameter `N` is +/// // inferred to be 5, thus creating array of 5 elements. /// let array = core::array::from_fn(|i| i); /// assert_eq!(array, [0, 1, 2, 3, 4]); /// ``` @@ -119,6 +124,14 @@ impl fmt::Display for TryFromSliceError { } } +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for TryFromSliceError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + impl TryFromSliceError { #[unstable( feature = "array_error_internals", @@ -173,6 +186,18 @@ impl<T, const N: usize> const BorrowMut<[T]> for [T; N] { } } +/// Tries to create an array `[T; N]` by copying from a slice `&[T]`. Succeeds if +/// `slice.len() == N`. +/// +/// ``` +/// let bytes: [u8; 3] = [1, 0, 2]; +/// +/// let bytes_head: [u8; 2] = <[u8; 2]>::try_from(&bytes[0..2]).unwrap(); +/// assert_eq!(1, u16::from_le_bytes(bytes_head)); +/// +/// let bytes_tail: [u8; 2] = bytes[1..3].try_into().unwrap(); +/// assert_eq!(512, u16::from_le_bytes(bytes_tail)); +/// ``` #[stable(feature = "try_from", since = "1.34.0")] impl<T, const N: usize> TryFrom<&[T]> for [T; N] where @@ -185,6 +210,18 @@ where } } +/// Tries to create an array `[T; N]` by copying from a mutable slice `&mut [T]`. +/// Succeeds if `slice.len() == N`. +/// +/// ``` +/// let mut bytes: [u8; 3] = [1, 0, 2]; +/// +/// let bytes_head: [u8; 2] = <[u8; 2]>::try_from(&mut bytes[0..2]).unwrap(); +/// assert_eq!(1, u16::from_le_bytes(bytes_head)); +/// +/// let bytes_tail: [u8; 2] = (&mut bytes[1..3]).try_into().unwrap(); +/// assert_eq!(512, u16::from_le_bytes(bytes_tail)); +/// ``` #[stable(feature = "try_from_mut_slice_to_array", since = "1.59.0")] impl<T, const N: usize> TryFrom<&mut [T]> for [T; N] where @@ -197,6 +234,18 @@ where } } +/// Tries to create an array ref `&[T; N]` from a slice ref `&[T]`. Succeeds if +/// `slice.len() == N`. +/// +/// ``` +/// let bytes: [u8; 3] = [1, 0, 2]; +/// +/// let bytes_head: &[u8; 2] = <&[u8; 2]>::try_from(&bytes[0..2]).unwrap(); +/// assert_eq!(1, u16::from_le_bytes(*bytes_head)); +/// +/// let bytes_tail: &[u8; 2] = bytes[1..3].try_into().unwrap(); +/// assert_eq!(512, u16::from_le_bytes(*bytes_tail)); +/// ``` #[stable(feature = "try_from", since = "1.34.0")] impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { type Error = TryFromSliceError; @@ -212,6 +261,18 @@ impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { } } +/// Tries to create a mutable array ref `&mut [T; N]` from a mutable slice ref +/// `&mut [T]`. Succeeds if `slice.len() == N`. +/// +/// ``` +/// let mut bytes: [u8; 3] = [1, 0, 2]; +/// +/// let bytes_head: &mut [u8; 2] = <&mut [u8; 2]>::try_from(&mut bytes[0..2]).unwrap(); +/// assert_eq!(1, u16::from_le_bytes(*bytes_head)); +/// +/// let bytes_tail: &mut [u8; 2] = (&mut bytes[1..3]).try_into().unwrap(); +/// assert_eq!(512, u16::from_le_bytes(*bytes_tail)); +/// ``` #[stable(feature = "try_from", since = "1.34.0")] impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { type Error = TryFromSliceError; @@ -375,7 +436,8 @@ impl<T: Copy> SpecArrayClone for T { macro_rules! array_impl_default { {$n:expr, $t:ident $($ts:ident)*} => { #[stable(since = "1.4.0", feature = "array_default")] - impl<T> Default for [T; $n] where T: Default { + #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] + impl<T> const Default for [T; $n] where T: ~const Default { fn default() -> [T; $n] { [$t::default(), $($ts::default()),*] } @@ -854,7 +916,7 @@ where mem::forget(guard); // SAFETY: All elements of the array were populated in the loop above. - let output = unsafe { MaybeUninit::array_assume_init(array) }; + let output = unsafe { array.transpose().assume_init() }; Ok(Try::from_output(output)) } |