rust-lang / rust-lang/rust-clippy

Prefer *_chunk APIs for extracting arrays from slices

Open
#16,396 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-lint
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

What it does

The following slice methods extract arrays from longer slices:

  • first_chunk and split_first_chunk (1.77, const 1.77)
  • first_chunk_mut and split_first_chunk_mut (1.77, const 1.83)
  • last_chunk (1.77, const 1.80) and split_last_chunk (1.77, const 1.77)
  • last_chunk_mut and split_last_chunk_mut (1.77, const 1.83)

They're not always applicable, but if existing code is slicing or calling split_at[_*] with a constant index and then immediately turning the result into an array via TryInto, using one of the *_chunk APIs can be clearer about an array being involved. (Being careful about whether the array is a reference or a value, of course!)

Advantage
  • Avoids using TryInto for a conversion that is infallible by construction.
  • In many cases the *_chunk APIs allow omitting the array length entirely; it'll be inferrable from context. (As with all type inference, this could also be considered a disadvantage.)
Drawbacks
  • There's no implicitly-panicking version of the *_chunk APIs, so even though there's no need to unwrap TryInto anymore, some of the transformations would introduce an explicit unwrap for the split point being in bounds. This can make the resulting code longer than the original code.
Example
// Before
u32::from_be_bytes(bytes[..4].try_into().unwrap())
// After
u32::from_be_bytes(*bytes.first_chunk().expect("slice is long enough"))
// Before
u32::from_be_bytes(bytes.get(..4)?.try_into().unwrap())
// After
u32::from_be_bytes(*bytes.first_chunk()?)
// Before
u32::from_be_bytes(bytes.get(bytes.len() - 4..)?.try_into().unwrap())
// After
u32::from_be_bytes(*bytes.last_chunk()?)
// Before
let (magic_number, contents) = bytes.split_at_checked(8)?;
check(magic_number.try_into().unwrap());
// After
let (magic_number, contents) = bytes.split_first_chunk::<8>()?;
check(magic_number);
// Before
let (contents, auth_tag) = bytes.split_at_mut(bytes.len() - 16);
cipher.write_auth_tag(auth_tag.try_into().unwrap());
// After
let (contents, auth_tag) = bytes.split_last_chunk_mut::<16>().expect("slice is long enough");
cipher.write_auth_tag(auth_tag);

A possible extension to also cover copy_from_slice when copying from an array, for clearer code and an avoided (optimizable) bounds check:

// Before
let (magic_number, contents) = bytes.split_at_mut(8);
magic_number.copy_from_slice(&MAGIC_U32.to_be_bytes());
// After
let (magic_number, contents) = bytes.split_first_chunk_mut::<8>().expect("slice is long enough");
*magic_number = MAGIC_U32.to_be_bytes();
Comparison with existing lints

No response

Additional Context

This operation is specifically interesting for pulling arrays out of slices. If someone wants to pull arrays out of arrays, the APIs in https://github.com/rust-lang/rust/issues/90091 may be a better choice…but the ideal interface for those is blocked on stronger generic const exprs.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue provides no repository files, tests, or entry points to start from. Begin by reviewing the listed slice and *_chunk examples and existing lint conventions, then define completion as detecting the described array-extraction patterns without overreaching into array-to-array APIs.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.