Skip to content

ACP: Provide TryFrom<&[T]> implementation for &[[T; N]] #201

Closed as not planned
@mina86

Description

@mina86

Proposal

Problem statement

Provide TryFrom<&[T]> implementation for &[[T; N]] as a more convenient wrapper around [T]::as_chunks.

Motivation, use-cases

Unstable [T]::as_chunks method allows converting &[T] into &[[T; N]]. However, to handle slices whose length doesn’t divide by N the method returns (chunks, remainder) tuple. If one wants to assert an empty remainder they may need to resort to destructuring the tuple and introducing if statement. Similarly, it doesn’t mesh nicely with method chaining. A chain of methods needs to be stopped to verify the second element of the returned tuple before proceeding.

Introducing TryFrom<&[T]> implementation for &[[T; N]] offers a Result-based interface for chunking a slice. Result integrates with many interfaces of the language which results in more concise code.

Compare:

// Before:

fn pairs(slice: &[u8]) -> Result<&[[u8; 2]]> {
    let (chunks, remainder) = slice.as_chunks::<2>();
    if remainder.is_empty() {
        Ok(chuns)
    } else {
        Err(SomeError)
    }
}

// Alternatively with let-else:

fn pairs(slice: &[u8]) -> Result<&[[u8; 2]]> {
    let (chunks, []) = slice.as_chunks::<2>() else {
        return Err(SomeError);
    };
    Ok(chunks)
}

// After, more concise with a single expression:

fn pairs(slice: &[u8]) -> Result<&[[u8; 2]]> {
    slice.try_into().map_err(|_| SomeError)
}
// Before, with use of let-else:

let bytes = get_bytes_in_a_vector();
let (chunks, []) = bytes.as_chunks() else {
    return Err(SomeError.into());
};
let u64s = chunks
    .into_iter()
    .map(|chunk| u64::from_le_bytes(*bytes))
    .collect::<Vec<_>>()

// After, single statement with no need for temporary variables:

let u64s = get_bytes_in_a_vector()
    .as_slice()
    .try_into::<&[[u8; 8]]>(bytes)
    .map_err(|_| SomeError)?
    .into_iter()
    .map(|chunk| u64::from_le_bytes(*bytes))
    .collect::<Vec<_>>();

Solution sketches

Solution is implemented in rust-lang/rust#105316 and has the form:

impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [[T; N]] {
    type Error = TryFromSliceError;

    fn try_from(slice: &'a [T]) -> Result<Self, Self::Error> {
        let (chunks, remainder) = slice.as_chunks::<N>();
        if remainder.is_empty() {
            Ok(chunks)
        } else {
            Err(TryFromSliceError(()))
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions