Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

There would need to be contractual declarations on the read method that the compiler is able to enforce that tells it that the input &mut slice has N elements clobbered based on the returned length. That’s basically what BorrowedBuf is accomplishing via the type system and runtime enforcement of the contract. Using a non-existent syntax:

    fn read<T, N: size_t>(&mut self, buf: &mut [MaybeUninit<T>] becomes &[T; N] after call) -> N {
        … enforces the body initializes N elements out of buf
    }
and then rules that &mut [T] can also be supplied to such functions that today could only accept a &mut [MaybeUninit<T>] transparently.

A more likely interface you could write today would look like:

    fn read_uninit<T>(&mut self, buf: &mut [MaybeUninit<T>]) -> (&[T], &[MaybeUninit<T>]) {
        … enforces the body initializes N elements out of buf
    }
You still have to cast &[T] into &[MaybeUninit<T>] somehow.


> You still have to cast &[T] into &[MaybeUninit<T>] somehow.

    unsafe{ std::mem::transmute(slice) }
This is probably the only way that will ever exist, because

    let slice: &mut [NonZeroU8] = ...;
    let slice_uninit: &mut [MaybeUninit<NonZeroU8>] = ...;
    let nonzero_uninit: &mut MaybeUninit<NonZeroU8> = &mut slice_uninit[0];
    *nonzero_uninit = MaybeUninit::zeroed();
    slice[0]; // Undefined behavior for sure by now.
Is all safe except for the cast.

I.e. MaybeUninit<T> allows you to write invalid bit-patterns to T, so you can't safely cast a reference to T to it (and if you do unsafely cast a reference to T to it you can't soundly write an invalid bit pattern). All current forms of safely making a MaybeUninit take ownership of the value they are declaring to be MaybeUninit for this reason.

I guess at some point we might get methods for this on types that can take on all bit patterns - if/when that's encoded as a trait.


I think an ergonomic way to do that would to have read return not an integer, but a slice of that integer’s length.

Problem would be: how do you express “you can only access the buffer you sent me through the read-only slice I returned, but you have to free that same buffer when you’re done calling me?

I think that can be done using a function creating a read buffer for a given input stream that

- during calls to read is ‘owned for writing’ by that stream (so, it has to borrow a capability that the creator of the buffer doesn’t have. I don’t think Rust currently supports that)

- where stream.read returns a read only slice whose lifetime is bound to that of the buffer

So, the creator of the buffer can only pass it to read to get a slice back that contains precisely the data read.

The stream can write to the entire buffer.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: