Use zero-copy APIs when sending data in perf application.
Performance difference:
1. First line is before
2. Second line is after (but with only the download write change)
```
│ Duration │ FBL | Upload Throughput | Download Throughput
──────┼───────────┼───────────┼───────────────────┼────────────────────
AVG │ 5.00ms │ 1.00ms │ 332.82 MiB/s │ 334.20 MiB/s
AVG │ 5.00ms │ 0.00ns │ 332.64 MiB/s │ 335.96 MiB/s
```
=> Makes less than 1%. Still neat to have
This extends the public quinn API to offer support for writing owned buffers.
Besides the universal `write_chunks` API which supports a variable amount
of buffers the API also offers convenience methods for writing either a
single buffer completely or an arbitrary amount of buffers completely.
When a frame contained data for an offset of 0, the transmit logic did not
fully fill a packet. The reason for this is that the logic reserved 1 byte for
writing an offset. However storing offset 0 doesn't require 1 byte,
because it will be encoded with a special flag in the message header.
Without GSO, this isn't a huge issue. It mostly means we are wasting
1 byte per datagram.
However with GSO, this actually leads to data corruption:
When using GSO, and packet isn't fully filled, it later gets padded
to MTU size. Padding a packet ending with a STREAM frame that
doesn't contain a length information is however invalid, and will let
the receiver assume the padding is part of part of the data. This means
the receiver will receive an extra `0` at the end of a stream - and
depending on the duplicate detection at the receiver either the 0
or the correct byte in the next packet will win.
This change modifies quinn-proto to allow callers to submit a list
of one or more owned `Bytes` chunks for transmission instead of
pure byte slices. This will provide a more efficient zero-copy
interface for applications which already make use of owned
`Bytes` buffers.
The internals of quinn-proto have been refactored in order to keep
the ability to pass `&[u8]` buffers and defer the conversion into
`Bytes` as long as possible, in order to avoid unnecessary allocations
if no data can be stored due to flow control.