bytes
bytes copied to clipboard
API to peek at integers of buffer
This is a feature request for the Buf
trait to provide an API to peek at an integer of the buffer without advancing the underlying cursor. E.g. there is get_u32
and it would be really useful to have the equivalent but non cursor advancing peek_u32
that returns the next u32
of buffer.
If this feature already exists, my apologies, but I seem to have missed it. If not, is there any reason it is not included?
Peeking is a bit harder. Buf
is basically a byte optimized iterator. In order to provide peaking of multiple bytes, you need to be able to rewind. Rewinding is not trivial to do for some implementations (single linked list, for example).
There are a few options. First, you can take T: Buf + Clone
. In which case, this implies that you can clone the buffer to "peek".
Another alternative is something I proposed in https://github.com/tokio-rs/bytes/issues/300, but this would work only for "bufs" that are in continuous memory.
@carllerche Those are fair points.
Maybe this could be a separate trait implemented only by buffers that abstract over contiguous memory, such as BytesMut
(at least as far as I understand it is contiguous, by inspecting its source? Maybe the trait could be called Peek
and offer the peek_<integer>
methods. What do you think? Have I missed something?
This is a bit unrelated, but I wanted to give you an idea since my use case involves tokio_codec
and as far as I know, you are its author.
My use case of this in implementing the Decoder
trait is to decode messages in a TCP based binary protocol, where messages are prefixed with a fixed size length header, whether the buffer has the full message, and only proceeding to decode (i.e. consume the bytes in the buffer) if it does. Now, this only works if the message length prefix is kept in the buffer until the whole message can be extracted (thus the need for peeking).
Currently I work around this limitation with the following pattern, exploiting the fact that Buf
is implemented for byte slices:
let mut buf: BytesMut = ...;
// ...
let mut tmp_buf = buf.bytes();
let payload_len = tmp_buf.get_u32() as usize;
// check that we got the full payload in the buffer (NOTE: we need
// to add the message length prefix's byte count to payload_len
// since the buffer cursor was not advanced and thus we need to
// consider the prefix too)
if buf.remaining() >= 4 + payload_len {
// we have the full message in the buffer so advance the buffer
// cursor past the message length header
buf.advance(4);
} else {
return Ok(None);
}
I would think this is a common pattern as I'm sure other protocols also employ length prefixes/headers. Is there a better way to do this?
I'm new to rust. May be this is a solution?
let mut len_bytes = [0; 4];
len_bytes.clone_from_slice(&bytesMut[0..4]);
let len = u32::from_be_bytes(len_bytes);