Moves, & Lifetimes - confused and stuck
⚓ Rust 📅 2026-04-26 👤 surdeus 👁️ 2I 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 )
}
}
}
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
🏷️ Rust_feed