Skip to content

Commit

Permalink
Rollup merge of #97594 - WaffleLapkin:array_tuple_conv, r=ChrisDenton
Browse files Browse the repository at this point in the history
Implement tuple<->array convertions via `From`

This PR adds the following impls that convert between homogeneous tuples and arrays of the corresponding lengths:
```rust
impl<T> From<[T; 1]> for (T,) { ... }
impl<T> From<[T; 2]> for (T, T) { ... }
/* ... */
impl<T> From<[T; 12]> for (T, T, T, T, T, T, T, T, T, T, T, T) { ... }

impl<T> From<(T,)> for [T; 1] { ... }
impl<T> From<(T, T)> for [T; 2] { ... }
/* ... */
impl<T> From<(T, T, T, T, T, T, T, T, T, T, T, T)> for [T; 12] { ... }
```

IMO these are quite uncontroversial but note that they are, just like any other trait impls, insta-stable.
  • Loading branch information
Manishearth authored May 3, 2023
2 parents 473f916 + de10516 commit 84d8159
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 5 deletions.
20 changes: 20 additions & 0 deletions library/core/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,9 @@ mod prim_pointer {}
/// if the element type allows it. As a stopgap, trait implementations are
/// statically generated up to size 32.
///
/// Arrays of sizes from 1 to 12 (inclusive) implement [`From<Tuple>`], where `Tuple`
/// is a homogenous [prim@tuple] of appropriate length.
///
/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
/// an array. Indeed, this provides most of the API for working with arrays.
///
Expand Down Expand Up @@ -672,6 +675,13 @@ mod prim_pointer {}
/// move_away(roa);
/// ```
///
/// Arrays can be created from homogenous tuples of appropriate length:
///
/// ```
/// let tuple: (u32, u32, u32) = (1, 2, 3);
/// let array: [u32; 3] = tuple.into();
/// ```
///
/// # Editions
///
/// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call
Expand Down Expand Up @@ -774,6 +784,7 @@ mod prim_pointer {}
/// [`Borrow`]: borrow::Borrow
/// [`BorrowMut`]: borrow::BorrowMut
/// [slice pattern]: ../reference/patterns.html#slice-patterns
/// [`From<Tuple>`]: convert::From
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_array {}

Expand Down Expand Up @@ -1000,7 +1011,9 @@ mod prim_str {}
/// * [`Debug`]
/// * [`Default`]
/// * [`Hash`]
/// * [`From<[T; N]>`][from]
///
/// [from]: convert::From
/// [`Debug`]: fmt::Debug
/// [`Hash`]: hash::Hash
///
Expand Down Expand Up @@ -1051,6 +1064,13 @@ mod prim_str {}
/// assert_eq!(y, 5);
/// ```
///
/// Homogenous tuples can be created from arrays of appropriate length:
///
/// ```
/// let array: [u32; 3] = [1, 2, 3];
/// let tuple: (u32, u32, u32) = array.into();
/// ```
///
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_tuple {}

Expand Down
20 changes: 20 additions & 0 deletions library/core/src/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ macro_rules! tuple_impls {
}
}
}

#[stable(feature = "array_tuple_conv", since = "1.63.0")]
impl<T> From<[T; ${count(T)}]> for ($(${ignore(T)} T,)+) {
#[inline]
#[allow(non_snake_case)]
fn from(array: [T; ${count(T)}]) -> Self {
let [$($T,)+] = array;
($($T,)+)
}
}

#[stable(feature = "array_tuple_conv", since = "1.63.0")]
impl<T> From<($(${ignore(T)} T,)+)> for [T; ${count(T)}] {
#[inline]
#[allow(non_snake_case)]
fn from(tuple: ($(${ignore(T)} T,)+)) -> Self {
let ($($T,)+) = tuple;
[$($T,)+]
}
}
}
}

Expand Down
20 changes: 20 additions & 0 deletions library/std/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,9 @@ mod prim_pointer {}
/// if the element type allows it. As a stopgap, trait implementations are
/// statically generated up to size 32.
///
/// Arrays of sizes from 1 to 12 (inclusive) implement [`From<Tuple>`], where `Tuple`
/// is a homogenous [prim@tuple] of appropriate length.
///
/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
/// an array. Indeed, this provides most of the API for working with arrays.
///
Expand Down Expand Up @@ -672,6 +675,13 @@ mod prim_pointer {}
/// move_away(roa);
/// ```
///
/// Arrays can be created from homogenous tuples of appropriate length:
///
/// ```
/// let tuple: (u32, u32, u32) = (1, 2, 3);
/// let array: [u32; 3] = tuple.into();
/// ```
///
/// # Editions
///
/// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call
Expand Down Expand Up @@ -774,6 +784,7 @@ mod prim_pointer {}
/// [`Borrow`]: borrow::Borrow
/// [`BorrowMut`]: borrow::BorrowMut
/// [slice pattern]: ../reference/patterns.html#slice-patterns
/// [`From<Tuple>`]: convert::From
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_array {}

Expand Down Expand Up @@ -1000,7 +1011,9 @@ mod prim_str {}
/// * [`Debug`]
/// * [`Default`]
/// * [`Hash`]
/// * [`From<[T; N]>`][from]
///
/// [from]: convert::From
/// [`Debug`]: fmt::Debug
/// [`Hash`]: hash::Hash
///
Expand Down Expand Up @@ -1051,6 +1064,13 @@ mod prim_str {}
/// assert_eq!(y, 5);
/// ```
///
/// Homogenous tuples can be created from arrays of appropriate length:
///
/// ```
/// let array: [u32; 3] = [1, 2, 3];
/// let tuple: (u32, u32, u32) = array.into();
/// ```
///
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_tuple {}

Expand Down
13 changes: 10 additions & 3 deletions tests/ui/issues/issue-32709.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ LL | Err(5)?;
| ^ the trait `From<{integer}>` is not implemented for `()`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following other types implement trait `FromResidual<R>`:
<Result<T, F> as FromResidual<Result<Infallible, E>>>
<Result<T, F> as FromResidual<Yeet<E>>>
= help: the following other types implement trait `From<T>`:
<(T, T) as From<[T; 2]>>
<(T, T, T) as From<[T; 3]>>
<(T, T, T, T) as From<[T; 4]>>
<(T, T, T, T, T) as From<[T; 5]>>
<(T, T, T, T, T, T) as From<[T; 6]>>
<(T, T, T, T, T, T, T) as From<[T; 7]>>
<(T, T, T, T, T, T, T, T) as From<[T; 8]>>
<(T, T, T, T, T, T, T, T, T) as From<[T; 9]>>
and 4 others
= note: required for `Result<i32, ()>` to implement `FromResidual<Result<Infallible, {integer}>>`

error: aborting due to previous error
Expand Down
10 changes: 8 additions & 2 deletions tests/ui/suggestions/issue-71394-no-from-impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ LL | let _: &[i8] = data.into();
|
= help: the following other types implement trait `From<T>`:
<&'input [u8] as From<gimli::read::endian_slice::EndianSlice<'input, Endian>>>
<[T; LANES] as From<Simd<T, LANES>>>
<[bool; LANES] as From<Mask<T, LANES>>>
<[T; 10] as From<(T, T, T, T, T, T, T, T, T, T)>>
<[T; 11] as From<(T, T, T, T, T, T, T, T, T, T, T)>>
<[T; 12] as From<(T, T, T, T, T, T, T, T, T, T, T, T)>>
<[T; 1] as From<(T,)>>
<[T; 2] as From<(T, T)>>
<[T; 3] as From<(T, T, T)>>
<[T; 4] as From<(T, T, T, T)>>
and 7 others
= note: required for `&[u8]` to implement `Into<&[i8]>`

error: aborting due to previous error
Expand Down

0 comments on commit 84d8159

Please sign in to comment.