Search code examples
rustmutexautomatic-ref-counting

Is it possible to convert a &[T] or Vec<T> to Arc<Mutex<[T]>>?


Consider the following

use std::sync::{Arc,Mutex};

fn arc_mutex_from_slice<T>(v: &[T]) -> Arc<Mutex<[T]>> {
    todo!();
}

fn main() {
    let v = vec![1,2,3];
    println!("{:#?}", arc_mutex_from_slice(&v[..]));
}

Is it possible to implement arc_mutex_from_slice? It is possible to implement this conversion for Arc<Mutex<Box<[T]>>> or Arc<Mutex<Vec<T>>>, but both of those add another unnecessary allocation/indirection.

The type Arc<Mutex<[T]>> is valid and can be initialized when the slice's size is known.

let x = Arc::new(Mutex::new([1,2,3]));

But I can't find any way of achieving this when the slice's size is unknown. Naively trying to implement arc_mutex_from_slice as follows does not compile.

fn arc_mutex_from_slice<T>(v: &[T]) -> Arc<Mutex<[T]>> {
    return Arc::new(Mutex::new(*v));
}
error[E0277]: the size for values of type `[T]` cannot be known at compilation time
 --> src/main.rs:4:21
  |
4 |     return Arc::new(Mutex::new(*v));
  |            -------- ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
  |            |
  |            required by a bound introduced by this call
  |
  = help: within `Mutex<[T]>`, the trait `Sized` is not implemented for `[T]`
  = note: required because it appears within the type `Mutex<[T]>`
note: required by a bound in `Arc::<T>::new`

Could any unsafe magic help with this?


Solution

  • As of writing, for safe Rust, you can do it, but only if the size of the array when allocation happens is known at compile time:

    let v: Arc<Mutex<[u8]>> = Arc::new(Mutex::new([0;16]));
    

    This essentially casts an Arc<Mutex<[u8;16]>> to an Arc<Mutex<[u8]>>.

    However there is no way currently to do this safely with an array whose size is only known at runtime. The tricky part is that you would need to create the unsized Mutex<[u8]> and move it to the constructor of Arc, but moving values currently requires that the compiler knows their sizes.

    RFC 1909 may help the situation, but has been open since 2017 with no end in sight.


    As for unsafe... You could possibly allocate a section of memory that can hold both a Mutex<()> as well as the array, and access it manually via byte offsets. You have to be careful though - you may need padding in between the mutex and the array to satisfy the array element's alignment, and be sure you're not violating any aliasing or providence rules.