summaryrefslogtreecommitdiffstats
path: root/library/core/src/array
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/core/src/array/equality.rs7
-rw-r--r--library/core/src/array/iter.rs59
-rw-r--r--library/core/src/array/mod.rs68
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))
}