Confused about Borrowed value does not live long enough

I'm writing a filesystem utils in rust for userspace program and here's the snippet i wrote. It's relative long but i will keep it concise here.


pub(crate) struct TempBuffer {
    block: Block,
    maxsize: usize,
}

pub(crate) trait Buffer<'a> {
    fn content_mut(&'a mut self) -> &'a mut [u8];
    fn content(&'a self) -> &'a [u8];
}

impl TempBuffer {
    pub(crate) fn new(block: Block, maxsize: usize) -> Self {
        Self { block, maxsize }
    }
}

impl<'a> Buffer<'a> for TempBuffer {
    fn content_mut(&'a mut self) -> &'a mut [u8] {
        &mut self.block[0..self.maxsize]
    }
    fn content(&'a self) -> &'a [u8] {
        &self.block[0..self.maxsize]
    }
}


impl<'a, 'b, T, U> Iterator for TempBufferIter<'a, 'b, T, U>
where
    T: SuperBlockInfo<'a, U>,
    U: FileBackend,
{
    type Item = TempBuffer;
    fn next(&mut self) -> Option<Self::Item> {
          ...
    }
}


pub(crate) struct DirCollection<'a> {
    data: &'a [u8],
    offset: usize,
    total: usize,
}


impl<'a> DirCollection<'a> {
    pub(crate) fn new(buffer: &'a [u8]) -> Self {
        let desc: &'a DirentDesc = unsafe { &*(buffer.as_ptr() as *const DirentDesc) };
        Self {
            data: buffer,
            offset: 0,
            total: desc.nameoff as usize / core::mem::size_of::<DirentDesc>(),
        }
    }
}

impl<'a, T> SuperBlockInfo<'a, T> for RawFileSystem<T>
where
    T: FileBackend,
{

    fn find_nid(&self, inode: &Inode, name: &str) -> Option<Nid> {
        for buf in self.content_iter(inode){
            for dirent in DirCollection::new(buf.content()) {
                if dirent.dirname(buf.content()) == name.as_bytes() {
                    return Some(dirent.desc.nid);
                }
            }
        }
        None
    }
    fn content_iter(&'a self, inode: &Inode) -> impl Iterator<Item = impl Buffer<'a>> {
        TempBufferIter::new(&self.backend, MapIter::new(self, inode))
    }
}

This code won't compile with this error.

error[E0597]: `buf` does not live long enough
   |
24 |         for buf in self.content_iter(inode){
   |             --- binding `buf` declared here
25 |             for dirent in DirCollection::new(buf.content()) {
   |                                              ^^^ borrowed value does not live long enough
...
30 |         }
   |         -
   |         |
   |         `buf` dropped here while still borrowed
   |         borrow might be used here, when `buf` is dropped and runs the destructor for type `impl data::Buffer<'_>`

I believe this buf simply outlives the inner loop and I just don't don't knowwhy borrow checker fails here :frowning: I've been trying to resolve this for a long time but i simply cannot find a workaround. Any help or suggestions will be much appreciated. Thanks!

BTW. Are there any ways that i can get detailed lifetime annotations of these scopes so that i can retrieve at least some additional information to diagnose the problem myself? It always seems like a black box to me when i try to understand what happens inside the borrow checker. Whenever i fix it , i often just don't understand why i fix it and why it works. I came from C and i know that lifetime is a good programming model but i find it too daunting to adapt to it.

1 Like

Most likely the problem is the definition of the Buffer trait. It should probably look like this:

pub(crate) trait Buffer {
    fn content_mut(&mut self) -> &mut [u8];
    fn content(&self) -> &[u8];
}

With the current definition, you are explicitly saying that calls to content must borrow the buffer for the lifetime 'a, and in find_nid that lifetime will end after the call to find_nid ends.

4 Likes

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.