Trying to move a slice out of a closure

I'm having a problem with lifetimes but I first need to understand if I understand the problem correctly, and then if I have an alternative without having to copy the slice to another slice

impl<'a> TcpSocket<'a> {
    //...
    pub fn recv<'b, F, R>(&'b mut self, f: F) -> Result<R>
            where F: FnOnce(&'b mut [u8]) -> (usize, R) {
        self.recv_impl(|rx_buffer| {
            rx_buffer.dequeue_many_with(f)
        })
    }
    //...
}

This is how it's used:

fn main() {
    //...
    State::Response if socket.can_recv() => {
            socket.recv(|data| {
            println!("{}", str::from_utf8(data).unwrap_or("(invalid utf8)"));
            //what I wanted to do: my_queue.lock().unwrap().push_back(data);
            (data.len(), ())
            }).unwrap();
            State::Response
    }
}

If I understood correctly, the lifetime of the data slice is bound to th lifetime of the socket itself, because of pub fn recv<'b, F, R>(&'b mut self, f: F). So I can't, for example, insert this slice into a queue that outlives socket. Am I right?

I'm trying to see if I have an exit here without having to copy the slice to a new one, and without modifying the lifetimes because they're from a library. I want to take it ouside of the scope of that lambda function and pass it to a queue.

I know it's kinda obvious that I cant put in a queue a slice that belongs to an object that might get destructed before the queue, but I actually want to move this slice. Perhaps there's a way? Because it looks like this slice is created on the scope of the recv function. So if it's created there I can maybe do something?

Here's the full souce if anyone wants to take a look: https://github.com/Dirbaio/smoltcp/blob/802c46305a7f4a69f30654d0461fad2f749bfc82/src/socket/tcp.rs#L752

In my mind, these are kind-of conflicting requirements. The only way to “move” something without “copying” the whole thing is when the data lives on the heap. In that case, all you need to do would be to pass the pointer, and the responsibility over that piece of heap memory can go with it. This would require the use of something else than just slices though, since they do, in general, not need to live on the heap.

In this particular case, as far as I can tell, the slice in question is just a pointer into a receive-buffer. On the next call to recv this data could very well be overwritten. Hence, if you want to extend the lifetime of the slice in question for longer than until the next call to recv, then copying the data is unavoidable. You don’t provide too much detail around the main function, so I don’t know if you even want to call recv multiple times. Well, actually, no matter if you want to do it in this particular case, as long as your TcpSocket API just allows another recv call, all you can do to extend the lifetime is to copy the data.

1 Like

It’s actually bound to the lifetime of the mutable borrow of self: you have to give up your reference to data before anything else uses the receiving socket. Presumably, this is to allow socket’s internal buffer to be reused for future packets.

This design allows programs that want to ignore some of the incoming data to extract only what they need, without the expense of copying the entire packet. In this case, where you want to keep everything, the explicit copy isn’t wasteful: something has to copy the data out of the receive buffer; the library doesn’t, so it has to be you.

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.