The `is_unique` entry in the vtable for `Bytes` created from a shared
`BytesMut` just called the `shared_is_unique` function from the `bytes`
module. However, that function dereferences the `data` argument` as
`bytes::Shared`, but the actual underlying type is `bytes_mut::Shared`.
* set len a little more concisely
* inline set_end
* remove kind assertions
* remove a duplicate assertion
* remove redundant assertion and min
* rename set_start to advance_unchecked
Back in #362, an assertion was added to ensure that the alignment of
bytes::Shared is even so we can use the least significant bit as a flag.
bytes_mut::Shared uses the same technique but has no such assertion so
I've added one here.
tokio::io::ReadBuf uses names `new` and `uninit` for its constructors.
For consistency with that, rename recently introduced UninitSlice
constructors to match those names.
Introduce UninitSlice::from_slice and UninitSlice::from_uninit_slice
methods which safely create Uninit slice from provided slice of maybe
uninitialised or initialised memory.
In addition, add `From<&mut [T]>` implementations (for `T=u8` and
`T=MaybeUninit<u8>`) which do conversion from slice to UninitSlice.
Closes: #552
This function can be hot in applications that do a lot of encoding. Ideally would do the same for `<BytesMut as BufMut>::put_slice` and `<BytesMut as BufMut::put_u8`.
When we freeze a BytesMut, we turn it into a Vec, and then convert that
to a Bytes. Currently, this happen using Vec::into_boxed_slice, which
reallocates to a slice of the same length as the Vev if the length and
the capacity are not equal. This can pose a performance problem if the
Vec is large or if this happens many times in a loop.
Instead, let's compare the length and capacity, and if they're the same,
continue to handle this using into_boxed_slice. Otherwise, since we
have a type of vtable which can handle a separate capacity, the shared
vtable, let's turn our Vec into that kind of Bytes. While this does not
avoid allocation altogether, it performs a fixed size allocation and
avoids any need to memcpy.
Fixes calls to `reserve` when the underlying shared buffer was already
big enough to fit the requested capacity. Previously a new even larger
buffer was created anyways. This could eventually lead to an OOM
condition.
This adds an unsafe method to convert a `&mut UninitSlice` into a
`&mut [MaybeUninit<u8>]`. This method is unsafe because some of the
bytes in the slice may be initialized, and the caller should not
overwrite them with uninitialized bytes.
This came about when auditing [tokio-util's udp frame], where they want
to pass the unitialized portion of a `BytesMut` to [ReadBuf::uninit].
They need to do this unsafe pointer casting in a few places, which
complicates audits. This method lets us document the safety invariants
the caller needs to maintain when doing this conversion.
[tokio-util's udp frame]: https://github.com/tokio-rs/tokio/blob/master/tokio-util/src/udp/frame.rs#L87
[ReadBuf::uninit]: https://docs.rs/tokio/latest/tokio/io/struct.ReadBuf.html#method.uninit