- The return type of `BufMut::bytes_mut` is now
`&mut [MaybeUninit<u8>]`.
- The argument type of `BufMut::bytes_vectored_mut` is now
`&mut [bytes::buf::IoSliceMut]`.
- `bytes::buf::IoSliceMut` is a `repr(transparent)` wrapper around an
`std::io::IoSliceMut`, but does not expose the inner bytes with a safe
API, since they might be uninitialized.
- `BufMut::bytesMut` and `BufMut::bytes_vectored_mut` are no longer
`unsafe fn`, since the types encapsulate the unsafety instead.
Bytes is a useful tool for managing multiple slices into the same region
of memory, and the other things it used to have been removed to reduce
complexity. The exact strategy for managing the multiple references is
no longer hard-coded, but instead backing by a customizable vtable.
- Removed ability to mutate the underlying memory from the `Bytes` type.
- Removed the "inline" (SBO) mechanism in `Bytes`. The reduces a large
amount of complexity, and improves performance when accessing the
slice of bytes, since a branch is no longer needed to check if the
data is inline.
- Removed `Bytes` knowledge of `BytesMut` (`BytesMut` may grow that
knowledge back at a future point.)
To make the library work as `no_std` we add an `std` feature which
is on by default. When it is off, we compile as `no_std` and make
parts of the API that require `std::io` conditional on the `std`
feature.
As consequence Buf::collect is removed as well, which is replaced with `Buf::into_bytes`. The advantage of `Buf::into_bytes` is that it can be optimized in cases where converting a `T: Buf` into a `Bytes` instance is efficient.
There's no reason the user should be forced to wrap it in BufReader in
case the trait is needed, because the Reader has all the bits for
supporting it naturally.
The property the Buff and BuffMut can return shorter slice is quite an
important detail. Nevertheless, while it is mentioned in the
documentation, the wording makes it relatively easy to overlook. This
tries to bring more attention to it.
With this if foo is a mutable slice, it is possible to do
foo.into_buf().put_u32_le(42);
Before this patch into_buf would create a Cursor<&'a [u8]> and it
would not be possible to write into it.
With this if foo is a mutable slice, it is possible to do
foo.into_buf().put_u32_le(42);
Before this patch into_buf would create a Cursor<&'a [u8]> and it
would not be possible to write into it.
This patch fixes the `copy_to_slice` function, rectifying the logic.
However, the incorrect code does not result in incorrect behavior as the
only case `cnt != src.len()` is during the final iteration, and since
`src.len()` is greater than `cnt` in that case, `off` will be
incremented by too much, but this will still trigger the `off <
dst.len()` condition.
The only danger is `src.len()` could cause an overflow.
* make Buf and BufMut usable as trait objects
- All the `get_*` and `put_*` methods that take `T: ByteOrder` have
a `where Self: Sized` bound added, so that they are only usable from
sized types. It was impossible to make `Buf` or `BufMut` into trait
objects before, so this change doesn't break anyone.
- Add `get_n_be`/`get_n_le`/`put_n_be`/`put_n_le` methods that can be
used on trait objects.
- Deprecate the export of `ByteOrder` and methods generic on it.
* remove deprecated ByteOrder methods
Removes the `_be` suffix from all methods, implying that the default
people should use is network endian.
- All the `get_*` and `put_*` methods that take `T: ByteOrder` have
a `where Self: Sized` bound added, so that they are only usable from
sized types. It was impossible to make `Buf` or `BufMut` into trait
objects before, so this change doesn't break anyone.
- Add `get_n_be`/`get_n_le`/`put_n_be`/`put_n_le` methods that can be
used on trait objects.
- Deprecate the export of `ByteOrder` and methods generic on it.
Fixes#163
I found this significantly improved a
[benchmark](https://gist.github.com/danburkert/34a7d6680d97bc86dca7f396eb8d0abf)
which calls `bytes_mut`, writes 1 byte, and advances the pointer with
`advance_mut` in a pretty tight loop. In particular, it seems to be the
inline annotation on `bytes_mut` which had the most effect. I also took
the opportunity to simplify the bounds checking in advance_mut.
before:
```
test encode_varint_small ... bench: 540 ns/iter (+/- 85) = 1481 MB/s
```
after:
```
test encode_varint_small ... bench: 422 ns/iter (+/- 24) = 1895 MB/s
```
As you can see, the variance is also significantly improved.
Interestingly, I tried to change the last statement in `bytes_mut` from
```
&mut slice::from_raw_parts_mut(ptr, cap)[len..]
```
to
```
slice::from_raw_parts_mut(ptr.offset(len as isize), cap - len)
```
but, this caused a very measurable perf regression (almost completely
negating the gains from marking bytes_mut inline).
The `Source` trait was essentially covering the same case as `IntoBuf`,
so remove it.
While technically a breaking change, this should not have any impact due
to:
1) There are no reverse dependencies that currently depend on `bytes`
2) Source was not supposed to be implemented externally
3) IntoBuf provides the same implementations as `Source`
Given these points, the change should be safe to apply.