How to use `&mut [MaybeUninit<u8>]` safely?

I have an interface like write(input: &[u8], output: &mut [u8]) but I want to offer an interface like write(input: &[u8], output: &mut [MaybeUninit<u8>]) as well, so that uninitialized memory can be passed. That change is straightforward, I can just use output[i].write(..) instead of output[i] = ...
But now I want to reuse this implementation for the existing write(input: &[u8], output: &mut [u8]) interface. It's not in general safe to transmute or convert &mut [u8] to &mut [MaybeUninit<u8>] because MaybeUninit::uninit could be written and then the original ref could be used to read unitialized data. Is it "enough" to ensure that the code I pass the MaybeUninit only writes initialized data? Or is this an unacceptable use of unsafe?

There are a number of options outlined in this article but that's all nightly at the moment.

How would a responsible implementation do this on stable rust?

The blog mentions some unstable standard library APIs, but the Buffer trait the author envisioned does not rely on these. In fact, the author even published their Buffer trait, which you can use on stable Rust.

2 Likes

You can use

fn write(input: &[u8], output: &mut UninitSlice)

with UninitSlice from the bytes crate.

1 Like