Moves, & Lifetimes - confused and stuck

⚓ Rust    📅 2026-04-26    👤 surdeus    👁️ 2      

surdeus

I am working on a parser for a binary stream read from a spi flash memory chip. The due to the data size (20-40 megabyte data items), and some other crypto things [ signature and encryption] I cannot create vectors on the heap.

Thus, I need to do all of this work with REFERENCES to slices so that i can accomplish "zero copy" and that is where I am getting stuck with lifetimes {again}. Its not getting into or through my thick head... and why is it that I need TWO lifetimes, one for the IMPL and one for the struct?

What is in the playground is a greatly reduced snip of code from the larger applciation.

/// This is a buffer that is read/wrote to/from a spi flash device.
struct Buffer<'a> {
    cursor : usize,
    databuf : &'a mut [u8]
}

/// The data in the flash is a "TAG-LENGTH-VALUE" type (recursively)
/// Very simular to a RIFF file found in Microsoft Multi-Media files
struct MyChunk<'a> {
    /// in memory, there is a 32bit little endian tag identifies the data type.
    tag :u32,   
    /// followed by a data length in bytes
    length : u32, 
    /// followed by a variable length data buffer.
    payload : Buffer<'a> 
    // The goal is to have a generic "chunk" object parser.
}

impl<'a> Buffer<'a> {
    
    /// Given a SLICE - return a new buffer 
    pub fn new( buf:  &'a mut [u8] ) -> Self {
        Self {
            cursor : 0,
            databuf : buf,
        }
    }
    
    /// From the existing buffer, at the cursor - create a new buffer/slice of LENGTH length.
    pub fn from_slice( self, length : usize ) -> Self {
        // Dimensions of the slice we are creating.
        let lhs : usize = self.cursor;
        let rhs : usize = lhs + length;
        Self {
            cursor : 0,
            databuf : &mut self.databuf[ lhs .. rhs ]
        }
    }
    
    /// One simple example of u32 value parser there are many others in the larger library.
    pub fn rd_u32_le(mut self) -> u32 {
        let b0 : u32  = self.databuf[ self.cursor + 0 ] as u32;
        let mut b1 : u32  = self.databuf[ self.cursor + 1 ] as u32;
        let mut b2 : u32  = self.databuf[ self.cursor + 2 ] as u32;
        let mut b3 : u32  = self.databuf[ self.cursor + 3 ] as u32;
        self.cursor = self.cursor + 4;
        
        // this one does little endian others do big endian.
        b3 = b3 << 24;
        b2 = b2 << 16;
        b1 = b1 << 8;
        // return the bytes combined as a u32.
        let result : u32 = (b0 | b1 | b2 | b3) + 0;
        result
    }
}

/// This represents a CHUNK of data in the binary image.
/// It begins with a U32 tag - identifying the data following.
/// Next is a U32 length (in bytes) of the data
/// We then takea slice of the buffer and return that as the payload of the object.
impl<'a> MyChunk<'a> {

    /// Given a ByteBuffer, read a object tag and object length.
    /// Return an Objectwith the "value" as buffer within the orignal buffer.
    pub fn parse_from_bb2( bb2 : Buffer<'a> ) -> Self {
        let tag : u32 = bb2.rd_u32_le();
        let length : u32 = bb2.rd_u32_le();
        Self {
            tag : tag,
            length : length,
            payload : bb2.from_slice( length as usize )
        }
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0382]: use of moved value: `bb2`
  --> src/lib.rs:68:28
   |
66 |     pub fn parse_from_bb2( bb2 : Buffer<'a> ) -> Self {
   |                            --- move occurs because `bb2` has type `Buffer<'_>`, which does not implement the `Copy` trait
67 |         let tag : u32 = bb2.rd_u32_le();
   |                             ----------- `bb2` moved due to this method call
68 |         let length : u32 = bb2.rd_u32_le();
   |                            ^^^ value used here after move
   |
note: `Buffer::<'a>::rd_u32_le` takes ownership of the receiver `self`, which moves `bb2`
  --> src/lib.rs:41:26
   |
41 |     pub fn rd_u32_le(mut self) -> u32 {
   |                          ^^^^

error[E0382]: use of moved value: `bb2`
  --> src/lib.rs:72:23
   |
66 |     pub fn parse_from_bb2( bb2 : Buffer<'a> ) -> Self {
   |                            --- move occurs because `bb2` has type `Buffer<'_>`, which does not implement the `Copy` trait
67 |         let tag : u32 = bb2.rd_u32_le();
68 |         let length : u32 = bb2.rd_u32_le();
   |                                ----------- `bb2` moved due to this method call
...
72 |             payload : bb2.from_slice( length as usize )
   |                       ^^^ value used here after move

For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` (lib) due to 2 previous errors

4 posts - 3 participants

Read full topic

🏷️ Rust_feed