What does the bytes crate do?

I'm reading bytes off a TcpStream (smol-rs) and I need to frame[1] and share[2] this data.

I heard about the bytes crate and how it can make this easier to do. But despite pouring over it's docs page, I just can't figure out what it is that it provides me that I can't do just as easy with a mutable array or vec? It appears to have an internal cursor that I can advance, but it seems like the same amount of work as just having a manual cursor in the form of an int.

let mut buf = BytesMut::zeroed(1024);
let n = stream.read(&mut buf).await.unwrap();
// some loop later
let n = stream.read(&mut buf).await.unwrap();
let mut buf = [0; 1024];
let n = stream.read(&mut buf).await.unwrap();
// some loop later
let n = stream.read(&mut buf).await.unwrap();

These do the same thing from a user observation. buf.advance(n) is just cursor_int += n. I already get the same bunch of iterators with regular arrays and slice and vecs like joins and concats etc. This is an extremely popular crate, what am I not getting?


  1. each line is a header and at the end of the message is a body of x length. A Content-Length header field establishes the len of the body. ↩︎

  2. I do this by having the threads compete for a lock on the TcpStream in a select statement that branches to a broadcast channel. If they acquire the lock they get to read first from the stream and then broadcast what they read. ↩︎

1 Like

From the docs:

Bytes values facilitate zero-copy network programming by allowing multiple Bytes objects to point to the same underlying memory. This is managed by using a reference count to track when the memory is no longer needed and can be freed.

It's similar to a Vec<u8> with [u8] slices referring back to the Vec, but it avoids issues with the borrow checker via API design and reference counting.

1 Like

I guess.. But I just haven't had any such issues so far so can't imagine what the purported benefit is as an alternative.

1 Like

The reference-counted nature of bytes means you can parse things from a TCP stream and you won't have to worry about the parsed objects holding references into some temporary buffer with all the lifetime concerns that incurs. I found this especially helpful a while back when writing a streaming parser for work.

With Vec<u8> you either need to read data into a buffer and copy parts of it into a new Vec<u8> or String as they are parsed, or you go down the lifetimes path and can't read more bytes into your buffer until all parsed objects referencing it have gone out of scope.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.