rust-lang / rust-lang/rust

No way to get mutable reference to Vec member without expressing uniqueness over the full Vec

Open
#134,507 4 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-collections C-feature-request needs-acp T-libs
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I've ran into the following standard library defect. There appears to be no possible sound way to go from a Vec<T> to a &mut T without expressing uniqueness over the full Vec. Vec::as_mut_ptr does not suffice because it takes a &mut self which expresses unique access over the full vec. A function which goes from *mut Vec<T> -> *mut T is necessary, but missing. The same is true for *mut [T] -> *mut T.


Consider the following example, where I have a v: Vec<Vec<u32>> where m.len() == n and m[i].len() == t for all i. I have t threads and I now want to process this array mutably in parallel, transposed. For example suppose I want to do the following in-place cumulative sum:

(0..t).into_par_iter().map(|thread_idx| {
    let mut cumsum = 0;
    for i in 0..n {
        // This obviously doesn't work, but you can't write this soundly with pointers either.
        let x: &mut u32 = &mut v[i][thread_idx];
        cumsum += *x;
        *x = cumsum;
    }
})

As far as I can tell, there is no way to write this soundly without introducing (potentially significant) overhead at all. The only way to write this soundly is to first create a temporary array of pointers and to modify the inner loop to use those pointers:

let ptrs: Vec<*mut u32> = v.iter_mut().map(|vi| vi.as_mut_ptr()).collect();
    // ...
        let x: &mut u32 = unsafe { &mut *ptrs[i].add(thread_idx) };
}

I really think the standard library should offer some kind of way to write this loop soundly without the unnecessary overhead of creating a pointer array. The simplest solution I think is to add functions which go from *mut Vec<T> -> *mut T and *mut [T] -> *mut T without creating an intermediate unique reference to the entire Vec or slice.

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

Start by reviewing Vec::as_mut_ptr and the raw-pointer conversions proposed for Vec and [T]. Evaluate whether these APIs can provide sound mutable element access without creating a unique reference to the whole collection, using the transposed parallel cumulative-sum example as the acceptance case. Done means a safe, justified standard-library API design or a documented reason the request cannot be supported.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
22/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.