Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize get_many_mut as get_disjoint_mut #134633

Merged
merged 1 commit into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions library/alloc/src/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ pub use core::slice::ArrayChunksMut;
pub use core::slice::ArrayWindows;
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
pub use core::slice::EscapeAscii;
#[unstable(feature = "get_many_mut", issue = "104642")]
pub use core::slice::GetManyMutError;
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
pub use core::slice::GetDisjointMutError;
#[stable(feature = "slice_get_slice", since = "1.28.0")]
pub use core::slice::SliceIndex;
#[cfg(not(no_global_oom_handling))]
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,5 +1075,5 @@ impl Error for crate::time::TryFromFloatSecsError {}
#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
impl Error for crate::ffi::FromBytesUntilNulError {}

#[unstable(feature = "get_many_mut", issue = "104642")]
impl Error for crate::slice::GetManyMutError {}
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
impl Error for crate::slice::GetDisjointMutError {}
115 changes: 56 additions & 59 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4530,7 +4530,7 @@ impl<T> [T] {
/// to single elements, while if passed an array of ranges it gives back an array of
/// mutable references to slices.
///
/// For a safe alternative see [`get_many_mut`].
/// For a safe alternative see [`get_disjoint_mut`].
///
/// # Safety
///
Expand All @@ -4540,44 +4540,42 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(get_many_mut)]
///
/// let x = &mut [1, 2, 4];
///
/// unsafe {
/// let [a, b] = x.get_many_unchecked_mut([0, 2]);
/// let [a, b] = x.get_disjoint_unchecked_mut([0, 2]);
/// *a *= 10;
/// *b *= 100;
/// }
/// assert_eq!(x, &[10, 2, 400]);
///
/// unsafe {
/// let [a, b] = x.get_many_unchecked_mut([0..1, 1..3]);
/// let [a, b] = x.get_disjoint_unchecked_mut([0..1, 1..3]);
/// a[0] = 8;
/// b[0] = 88;
/// b[1] = 888;
/// }
/// assert_eq!(x, &[8, 88, 888]);
///
/// unsafe {
/// let [a, b] = x.get_many_unchecked_mut([1..=2, 0..=0]);
/// let [a, b] = x.get_disjoint_unchecked_mut([1..=2, 0..=0]);
/// a[0] = 11;
/// a[1] = 111;
/// b[0] = 1;
/// }
/// assert_eq!(x, &[1, 11, 111]);
/// ```
///
/// [`get_many_mut`]: slice::get_many_mut
/// [`get_disjoint_mut`]: slice::get_disjoint_mut
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
#[unstable(feature = "get_many_mut", issue = "104642")]
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub unsafe fn get_many_unchecked_mut<I, const N: usize>(
pub unsafe fn get_disjoint_unchecked_mut<I, const N: usize>(
cuviper marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
indices: [I; N],
) -> [&mut I::Output; N]
where
I: GetManyMutIndex + SliceIndex<Self>,
I: GetDisjointMutIndex + SliceIndex<Self>,
{
// NB: This implementation is written as it is because any variation of
// `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy,
Expand Down Expand Up @@ -4616,42 +4614,40 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(get_many_mut)]
///
/// let v = &mut [1, 2, 3];
/// if let Ok([a, b]) = v.get_many_mut([0, 2]) {
/// if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) {
/// *a = 413;
/// *b = 612;
/// }
/// assert_eq!(v, &[413, 2, 612]);
///
/// if let Ok([a, b]) = v.get_many_mut([0..1, 1..3]) {
/// if let Ok([a, b]) = v.get_disjoint_mut([0..1, 1..3]) {
/// a[0] = 8;
/// b[0] = 88;
/// b[1] = 888;
/// }
/// assert_eq!(v, &[8, 88, 888]);
///
/// if let Ok([a, b]) = v.get_many_mut([1..=2, 0..=0]) {
/// if let Ok([a, b]) = v.get_disjoint_mut([1..=2, 0..=0]) {
/// a[0] = 11;
/// a[1] = 111;
/// b[0] = 1;
/// }
/// assert_eq!(v, &[1, 11, 111]);
/// ```
#[unstable(feature = "get_many_mut", issue = "104642")]
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub fn get_many_mut<I, const N: usize>(
pub fn get_disjoint_mut<I, const N: usize>(
&mut self,
indices: [I; N],
) -> Result<[&mut I::Output; N], GetManyMutError>
) -> Result<[&mut I::Output; N], GetDisjointMutError>
where
I: GetManyMutIndex + SliceIndex<Self>,
I: GetDisjointMutIndex + SliceIndex<Self>,
{
get_many_check_valid(&indices, self.len())?;
// SAFETY: The `get_many_check_valid()` call checked that all indices
get_disjoint_check_valid(&indices, self.len())?;
// SAFETY: The `get_disjoint_check_valid()` call checked that all indices
// are disjunct and in bounds.
unsafe { Ok(self.get_many_unchecked_mut(indices)) }
unsafe { Ok(self.get_disjoint_unchecked_mut(indices)) }
}

/// Returns the index that an element reference points to.
Expand Down Expand Up @@ -4993,26 +4989,26 @@ impl<T, const N: usize> SlicePattern for [T; N] {
/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
/// comparison operations.
#[inline]
fn get_many_check_valid<I: GetManyMutIndex, const N: usize>(
fn get_disjoint_check_valid<I: GetDisjointMutIndex, const N: usize>(
indices: &[I; N],
len: usize,
) -> Result<(), GetManyMutError> {
) -> Result<(), GetDisjointMutError> {
// NB: The optimizer should inline the loops into a sequence
// of instructions without additional branching.
for (i, idx) in indices.iter().enumerate() {
if !idx.is_in_bounds(len) {
return Err(GetManyMutError::IndexOutOfBounds);
return Err(GetDisjointMutError::IndexOutOfBounds);
}
for idx2 in &indices[..i] {
if idx.is_overlapping(idx2) {
return Err(GetManyMutError::OverlappingIndices);
return Err(GetDisjointMutError::OverlappingIndices);
}
}
}
Ok(())
}

/// The error type returned by [`get_many_mut`][`slice::get_many_mut`].
/// The error type returned by [`get_disjoint_mut`][`slice::get_disjoint_mut`].
///
/// It indicates one of two possible errors:
/// - An index is out-of-bounds.
Expand All @@ -5022,74 +5018,75 @@ fn get_many_check_valid<I: GetManyMutIndex, const N: usize>(
/// # Examples
///
/// ```
/// #![feature(get_many_mut)]
/// use std::slice::GetManyMutError;
/// use std::slice::GetDisjointMutError;
///
/// let v = &mut [1, 2, 3];
/// assert_eq!(v.get_many_mut([0, 999]), Err(GetManyMutError::IndexOutOfBounds));
/// assert_eq!(v.get_many_mut([1, 1]), Err(GetManyMutError::OverlappingIndices));
/// assert_eq!(v.get_disjoint_mut([0, 999]), Err(GetDisjointMutError::IndexOutOfBounds));
/// assert_eq!(v.get_disjoint_mut([1, 1]), Err(GetDisjointMutError::OverlappingIndices));
/// ```
#[unstable(feature = "get_many_mut", issue = "104642")]
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GetManyMutError {
pub enum GetDisjointMutError {
/// An index provided was out-of-bounds for the slice.
IndexOutOfBounds,
/// Two indices provided were overlapping.
OverlappingIndices,
}

#[unstable(feature = "get_many_mut", issue = "104642")]
impl fmt::Display for GetManyMutError {
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
impl fmt::Display for GetDisjointMutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
GetManyMutError::IndexOutOfBounds => "an index is out of bounds",
GetManyMutError::OverlappingIndices => "there were overlapping indices",
GetDisjointMutError::IndexOutOfBounds => "an index is out of bounds",
GetDisjointMutError::OverlappingIndices => "there were overlapping indices",
};
fmt::Display::fmt(msg, f)
}
}

mod private_get_many_mut_index {
mod private_get_disjoint_mut_index {
use super::{Range, RangeInclusive, range};

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
pub trait Sealed {}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for usize {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for Range<usize> {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for RangeInclusive<usize> {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for range::Range<usize> {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for range::RangeInclusive<usize> {}
}

/// A helper trait for `<[T]>::get_many_mut()`.
/// A helper trait for `<[T]>::get_disjoint_mut()`.
///
/// # Safety
///
/// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`,
/// it must be safe to index the slice with the indices.
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
pub unsafe trait GetManyMutIndex: Clone + private_get_many_mut_index::Sealed {
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
pub unsafe trait GetDisjointMutIndex:
Clone + private_get_disjoint_mut_index::Sealed
{
/// Returns `true` if `self` is in bounds for `len` slice elements.
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
fn is_in_bounds(&self, len: usize) -> bool;

/// Returns `true` if `self` overlaps with `other`.
///
/// Note that we don't consider zero-length ranges to overlap at the beginning or the end,
/// but do consider them to overlap in the middle.
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
fn is_overlapping(&self, other: &Self) -> bool;
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for usize {
unsafe impl GetDisjointMutIndex for usize {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
*self < len
Expand All @@ -5101,9 +5098,9 @@ unsafe impl GetManyMutIndex for usize {
}
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for Range<usize> {
unsafe impl GetDisjointMutIndex for Range<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
(self.start <= self.end) & (self.end <= len)
Expand All @@ -5115,9 +5112,9 @@ unsafe impl GetManyMutIndex for Range<usize> {
}
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for RangeInclusive<usize> {
unsafe impl GetDisjointMutIndex for RangeInclusive<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
(self.start <= self.end) & (self.end < len)
Expand All @@ -5129,9 +5126,9 @@ unsafe impl GetManyMutIndex for RangeInclusive<usize> {
}
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for range::Range<usize> {
unsafe impl GetDisjointMutIndex for range::Range<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
Range::from(*self).is_in_bounds(len)
Expand All @@ -5143,9 +5140,9 @@ unsafe impl GetManyMutIndex for range::Range<usize> {
}
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for range::RangeInclusive<usize> {
unsafe impl GetDisjointMutIndex for range::RangeInclusive<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
RangeInclusive::from(*self).is_in_bounds(len)
Expand Down
1 change: 0 additions & 1 deletion library/coretests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
#![feature(freeze)]
#![feature(future_join)]
#![feature(generic_assert_internals)]
#![feature(get_many_mut)]
#![feature(hasher_prefixfree_extras)]
#![feature(hashmap_internals)]
#![feature(inline_const_pat)]
Expand Down
Loading
Loading