Seeking Guidance on Rust Lifetimes for TCP Byte Reassembly with Slices

Hello everyone,

I'm new here and if something is not clear in my description, please let me know.

I've been working through the CS144 labs and trying to implement them in Rust. I've run into an issue that seems to be related to lifetimes and I would appreciate some guidance.

For TCP byte reassembly, I intended to use slices to minimize copying. However, I encountered a problem when writing test code where I used a BTreeMap to cache &[u8] with a 'a lifetime annotation.

pub struct StreamReassembler<'a> {
    unassembled: BTreeMap<u64, (&'a [u8], u64)>,
    …
}
pub trait StreamReassemblerTrait<'a> {
    fn push_substring(&'a mut self, data: &'a [u8], index: u64, eof: bool); // Stream reassembly
}

When writing the test code under /tests/, I ran into an issue where calling test.bytes_assembled(2) results in an error saying: cannot borrow test as immutable because it is also borrowed as mutable immutable borrow occurs here

pub(crate) struct ReassemblerTestHarness<'a> {
    stream_reassembler: StreamReassembler<'a>,
}

impl<'a> ReassemblerTestHarness<'a> {
…
    pub(crate) fn submit_segment(&'a mut self, data: &'a [u8], index: u64, eof: bool) {
        self.stream_reassembler.push_substring(data, index, eof);
    }
    pub(crate) fn bytes_assembled(&self, bytes: usize) { xxx }
}

fn test1() {
    let mut test = ReassemblerTestHarness::new(2);
    test.submit_segment(b"ab", 0, false);
    test.bytes_assembled(2);
}

From reviewing my Rust knowledge, it seems that the &'a mut self and data: &'a [u8] lifetimes being equal is causing the error after calling submit_segment — I can no longer have an immutable borrow...

In this scenario, if I still need to store slices in the StreamReassembler instead of copying into a Vec, how should I modify the code?

Or is this approach not in line with Rust's best practices?

I've been stuck on this for quite some time with no clear solution in sight... Any help would be greatly appreciated. :joy::joy:..

From what I can tell from what you've provided, I think you can just remove some incorrect lifetime annotations (the 'a on &mut self).

 impl<'a> ReassemblerTestHarness<'a> {
-    pub(crate) fn submit_segment(&'a mut self, data: &'a [u8], index: u64, eof: bool) {
+    pub(crate) fn submit_segment(&mut self, data: &'a [u8], index: u64, eof: bool) {
  impl<'a> ReassemblerTestHarness<'a> {
-    pub(crate) fn submit_segment(&'a mut self, data: &'a [u8], index: u64, eof: bool) {
+    pub(crate) fn submit_segment(&mut self, data: &'a [u8], index: u64, eof: bool) {

Read my reply over here (and the links) for some explanation on why you got borrow checker errors.

1 Like

Thanks for the reply, but

impl<'a> ReassemblerTestHarness<'a> {
    pub(crate) fn submit_segment(&mut self, data: &'a [u8], index: u64, eof: bool) {
        self.stream_reassembler.push_substring(data, index, eof);
    }
}

self.stream_reassembler.push_substring(data, index, eof); meet err: lifetime may not live long enough argument requires that '1 must outlive 'a.

Did you remove the pattern everywhere? I see now I accidentally made the same diff twice, I meant remove it from push_substring too.

You're right...it work.. it work..
I am wondering what I am doing all day....
Thank you so much.

1 Like

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.