Warning
This post was published 32 days ago. The information described in this article may have changed.
Hi everyone,
I am trying to manually implement a packet deserializer for a TCP stream using a partial zero copy approach. For this I decided to have a struct for each packet which will contain references to a buffer in memory.
I have also defined a deserialize trait to implement in every packet struct.
pub struct TCPClientAnnounce<'a> {
service_name: Cow<'a, str>,
}
pub trait DeserializeBinary<'a> : Sized {
fn deserialize(data: &'a [u8]) -> Result<(Self, usize), Error>;
}
impl<'a> DeserializeBinary<'a> for TCPClientAnnounce<'a> {
fn deserialize(data: &'a [u8]) -> Result<(Self, usize), Error> {
...
}
Since I have multiple packets, I also decided to implement a helper function that would execute a closure once all bytes have arrived:
async fn handle_next_packet<'a, T, F>(buffer: &'a mut Vec<u8>, tcp_stream: &mut TcpStream, mut handler: F) -> Result<(), GCLogNetworkError>
where
T: for<'de> DeserializeBinary<'de>,
F: FnMut(T),
{
loop {
tcp_stream.read(buffer).await?;
let result = T::deserialize(buffer);
match result {
Ok((packet, size)) => {
handler(packet);
buffer.drain(..size);
return Ok(());
}
// Non related error handling
}
}
}
Up until now everything seems to compile perfectly, but once I try to use this new function:
let mut buf = vec![0; BUFFER_PER_CONNECTION];
let service_name: String = String::new();
handle_next_packet(&mut buf, &mut socket, |p: &TCPClientAnnounce|{
service_name = p.service_name().to_string();
}).await?;
I get the following error:
implementation of `DeserializeBinary` is not general enough
`DeserializeBinary<'0>` would have to be implemented for the type `TCPClientAnnounce<'_>`, for any lifetime `'0`...
...but `DeserializeBinary<'1>` is actually implemented for the type `TCPClientAnnounce<'1>`, for some specific lifetime `'1`
Here I understand the error (I think), the lifetime of T should be specific to 'a. But if I remove the the HRTB and set the lifetime of T to be 'a, I get a lifetime error:
async fn handle_next_packet<'a, T, F>(buffer: &'a mut Vec<u8>, tcp_stream: &mut TcpStream, mut handler: F) -> Result<(), GCLogNetworkError>
where
T: DeserializeBinary<'a>,
F: FnMut(T),
{
loop {
tcp_stream.read(buffer).await?; // lifetime error: cannot borrow `buffer` as mutable more than once at a time
match result {
Ok((packet, size)) => {
handler(packet);
buffer.drain(..size);
return Ok(());
}
// Non related error handling
}
}
}
Is there a way I can make this work without resourcing to unsafe or owning data? This is not the first time that I encounter a similar problem, I still may have something to learn about HRTB's.
Also, I understand that are crates to this kind of stuff, but I plan to do this without any dependency and learn trough the process.
4 posts - 2 participants
🏷️ rust_feed