Search code examples
rustserde

Lifetime error with Serde in a Generic Function


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?


Solution

  • 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.