Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API to peek at integers of buffer #382

Open
vimpunk opened this issue Mar 28, 2020 · 3 comments
Open

API to peek at integers of buffer #382

vimpunk opened this issue Mar 28, 2020 · 3 comments

Comments

@vimpunk
Copy link

vimpunk commented Mar 28, 2020

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?

@carllerche
Copy link
Member

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 #300, but this would work only for "bufs" that are in continuous memory.

@vimpunk
Copy link
Author

vimpunk commented Mar 29, 2020

@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?

@alexniver
Copy link

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);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants