How to pass `&mut BytesMut` to a function that takes `&Bytes`?

How can we pass &mut BytesMut
to a function that takes &Bytes
?
Both types are from the Read more crate.
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
?
Can this issue be solved and how?
Answer
You can call BytesMut::freeze()
to get a Bytes
from a BytesMut
.
You need ownership, though. You can't do this with &mut BytesMut
because Bytes
is shareable-by-clone, so if you could make a &Bytes
from an &mut BytesMut
then you could also make a Bytes
from an &mut BytesMut
, which would then end up mutable again when the particular &mut
is released, and then you’d be in the position of having a Bytes
with contents that can get mutated, which is no good.
However, it might be a better idea to change your parse_len(bytes: &Bytes)
to parse_len(bytes: &[u8])
— since it doesn't return any slices of the Bytes
, just numbers, it doesn't need the powers of Bytes
. And it will accept both &Bytes
and &mut BytesMut
as arguments (via deref coercion).
(If this answer doesn't help, please add more code to your question — particularly, the code that is trying to use both the Decoder
and parse_len()
so we can see how they relate to each other.)
Enjoyed this article?
Check out more content on our blog or follow us on social media.
Browse more articles