I am trying to write a generic function that spawns a thread to deal with interaction with a server. Unfortunately, I am encountering a borrow bug that I don't understand. This is the code of my function :
fn spawn_response_thread<
'a,
MessageT:serde::Serialize + Send + 'static,
ResponseT: serde::Deserialize<'a> + 'static,
ResponseHandlingT: Fn(Result<ResponseT, String>) + Send + 'static
>
(
message : MessageT,
server_address : Option<(String,u16)>,
response_handler: ResponseHandlingT,
max_wait_time : Option<u64>
)
{
thread::spawn(
move ||
{
// First connect to a specific or random server
/**/
// Then send the desired request
/**/
// Loop to try receiving the message for a given time
let mut nb_wait = 0;
let mut buf;
let mut received = false;
/**/
// Send a response if there is one
if !received
{
response_handler(Err(format!("No response from server")));
}
else
{
let response : bincode::Result<ResponseT> = deserialize(&buf[..]);
match response
{
Ok(rcv) =>
{
response_handler(Ok(rcv));
}
Err(_) =>
{
response_handler(Err(format!("Error when trying to read response from server")));
}
}
}
} // <- line 353
);
}
(I cut parts of the code because I feel like there were irrelevant)
With this code, I am getting the following compilation error :
error[E0597]: `buf` does not live long enough
--> src/network.rs:340:81
|
230 | 'a,
| -- lifetime `'a` defined here
...
340 | let response : bincode::Result<ResponseType> = deserialize(&buf[..]);
| -------------^^^-----
| | |
| | borrowed value does not live long enough
| argument requires that `buf` is borrowed for `'a`
...
353 | }
| - `buf` dropped here while still borrowed
I don't understand why buf
would still be borrowed after deserialization.
What am I doing wrong?
The serde's Deserialize
trait has a lifetime 'de
. This lifetime is used to implemented zero-copy deserialization: avoiding copying e.g. strings, and instead using the already-exisiting buffer we deserialize from.
But if your object outlives the buffer, it cannot depend on it! In this case, you need a deserialization that lives forever, or for<'de> Deserialize<'de>
. Serde has a trait for that, DeserializeOwned
, which is essentially this: a shortcut for for<'de> Deserialize<'de>
. So what you need is to use DeserializeOwned
instead of Deserialize
:
fn spawn_response_thread<
MessageT: serde::Serialize + Send + 'static,
ResponseT: serde::de::DeserializeOwned + 'static,
ResponseHandlingT: Fn(Result<ResponseT, String>) + Send + 'static,
>(
message: MessageT,
server_address: Option<(String, u16)>,
response_handler: ResponseHandlingT,
max_wait_time: Option<u64>,
) {
// ...
}
For more take a look at Understanding deserializer lifetimes - serde.rs.