Follow up to https://github.com/tokio-rs/bytes/pull/689
* If `at == self.len()`, we already know `at <= self.len()`.
* If `at == 0`, we already know `at <= self.len()`.
* use checked_sub
* return when additional == 0
* move safe operation out of unsafe block
* use spare_capacity_mut instead of chunk_mut
We don't need to check capacity because it's already been reserved
above.
* Add safety comments
* refactor to use guard clauses
This would be better written with let-else, but we won't get that until
`MSRV >= 1.65.x`.
* use if-let instead of unwrap
* reduce scope of unsafe blocks
Co-authored-by: Alice Ryhl <[email protected]>
---------
Co-authored-by: Alice Ryhl <[email protected]>
A fundamental invariant of `reserve` is that it can extend capacity
while the stored data remains the same, even if it's moved to a new
allocation. As a result, `len` can never change during a call to
`reserve`.
* 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.