lucaspoffo/renet

Streaming API to write messages

Opened this issue · 5 comments

Shatur commented

Currently in order to send a message, I need to pass anything that converts into Bytes.
But this prevents users from re-using the memory. Bytes cheaply clonable, but can't grow, so users can't use it a buffer for snapshots. Vec<u8> can be used as a buffer for snapshots, but it needs to be cloned to send (because conversion from Vec<u8> to Bytes implemented only from owning value).
Maybe provide a streaming API instead where you write messages directly into Renet's message buffer?

Can you show an example of how the API would look. Not sure if I 100% understand it

Shatur commented

It would be great to have a concept of buffers inside Renet. Buffer is just Vec<u8>. Buffers can be "available" (the buffer is already acknowledged in reliable channel or was sent on an unreliable channel) or "in use" (the opposite of "available"). When user wants to write a message it requests a buffer from Renet. If all buffers are "in use", Renet just returns new Vec<u8>. If there is a buffer marked as "available" - Renet returns it as an owned value. Users writes data to this buffer and puts it back to Renet to any channel. Renet accepts this buffer and marks it as "in use" internally. After sending (or after the data becomes acknowledged for reliable channels) the buffer becomes "available" and next time user ask for a buffer, Renet will return it.

This seems to be an allocation problem. Since we use Bytes, we mostly delegate to it.
Some related discussions/PR in the Bytes crate:

Shatur commented

we mostly delegate to it.

The way Renet uses it, there is not much help from Bytes. User can preallocate BytesMut to write something, but after calling freeze to convert it into Bytes there is no way to write something else into it again.
SharedBuf would help in this case, but it have a cost. With the API I proposing there is no significant overhead. And we could keep convenient send_message and just add the passed Vec<u8> to the list of buffers "in use".

After some thinking I have an alternative proposal:
Copy all data passed to send_message and use buffers under the hood (reuse the memory). This approach is much simpler and still solves the problem I having.