I have a function parse_len(bytes: &Bytes) that parses length of a received message and it takes &Bytes. The first byte represents the type of a message, and the following bytes represent its length in bytes, and the length part ends with \r\n. Length is encoded as an arbitrary number of decimal digits. So, my function returns a tuple of the decoded/parsed message length and the number of bytes read to decode/parse the length. So, it doesn't need to take &mut BytesMut, and I have a lot of other functions that rely on &Bytes and not on &mut BytesMut, and I wouldn't like to change them, if possible. All those functions just read from the provided bytes and they don't need to mutate them.
I now want to include tokio-util::codec in the mix and I have a problem.
Its Decoder::decode() method takes src: &mut BytesMut and I have to pass src as input to my parse_len(bytes: &Bytes) function.
The error I'm getting is: arguments to this function are incorrect: expected &Bytes, found &mut BytesMut.
I haven't been able to find a workaround.
This issue is about removing mutability from &mut BytesMut, but it can't be done trivially, such as with &*, as &_, or similar.
Also, avoiding copying would be welcome as it obviously affects performance. The thing is we don't know in advance how long the sequence that represents length is. Sure, we could search for \r\n, but it all affects performance, as parse_len() will do it again. Is there a (simple) way to remove mutability from &mut BytesMut to &Bytes?
If you change the bytes argument of parse_len from &Bytes to &[u8], you can re-borrow &mut BytesMut as &[u8], thanks to BytesMutDeref<Target=[u8]> implementation:
use bytes::BytesMut;
fn parse_len(_: &[u8]) {}
fn foo(b: &mut BytesMut) {
parse_len(&b);
}
fn main() {
let mut b = BytesMut::from("foo");
foo(&mut b);
}
We're generally using the bytes crate for performance reasons, as its operations just increment the reference count.
Will your solution affect performance? I believe it shouldn't (by much) as we just de-reference and then re-borrow, and I don't see any copying involved. Is this the best we can do?
I considered this, too, but ultimately thought &[u8] was nicer, given that OP passes around &mut BytesMut and not BytesMut directly. They would have to pass it by value instead, or clone it to get an owned version. The latter would involve a copy of the underlying data.