1
votes

I'm trying to implement a simple parser for a byte stream.

I'm having troubles when I want to reuse a variable I declared previously,

fn read_data(asn_data: &mut Cursor<&[u8]>) -> Result<(u8, u8, Vec<u8>), Err> {
    let total_len = asn_data.get_ref().len();

    if total_len < 2 {
        return Err(1);
    }
    let d_type = asn_data.read_u8().unwrap();
    let d_len = asn_data.read_u8().unwrap();

    if (asn_data.position() + d_len as u64) > total_len as u64 {
        return Err(2);
    }

    let mut buf = vec![0; d_len as usize];

    match asn_data.read_exact(&mut buf) {
        Err(e) => Err(e),
        Ok(()) => Ok((d_type, d_len, buf)),
    }

}

fn parse_request(request: &[u8]) -> Option<u8> {

    if request.len() == 0 {
        return None;
    }

    let mut rdr = Cursor::new(request);
    let data_tuple = read_data(&mut rdr).unwrap();
    println!("{:02?}", data_tuple.2);

    rdr = Cursor::new(data_tuple.2.as_slice());
    let data_tuple = read_data(&mut rdr).unwrap();
    println!("{:02x?}", data_tuple.2);

    Some(1)
}

In the parse_request function I want to reuse rdr variable, but with the code shown above I get the next error when compiling:

error[E0597]: data_tuple.2 does not live long enough --> src/main.rs:80:23 | 80 | rdr = Cursor::new(data_tuple.2.as_slice()); | ^^^^^^^^^^^^ borrowed value does not live long enough ... 104 | } | - data_tuple.2 dropped here while still borrowed | = note: values in a scope are dropped in the opposite order they are created

error: aborting due to previous error

However if I write "let mut" when I use the 2nd time rdr variable, the code compiles and works fine...

let mut rdr = Cursor::new(data_tuple.2.as_slice());

I don't understand why... what I want is to reuse the variable instead to declare it again...

I tried with some examples/issues related to variable life time but I didn't get the solution for my case... and the solution I found I don't understand fully...

1
The easiest solution is to enable non-lexical lifetimes (or simply use the beta version of the 2018 edition).Sven Marnach
Redeclaring rdr makes sure it is declared after data_tuple, so the former can't outlive the latter. If you reuse the variable, the declaration order is the other way around, so rdr is only dropped after data_tuple, hence the error.Sven Marnach
Do you really have an error type called Err, which is in scope at the same time as the enum variant of the same name?Sven Marnach

1 Answers

2
votes

This is not connected with tuple lifetimes, this is just the drop order.

When the variables are defined in separate let statements in the same scope (that is, in the same block), they will be dropped in reverse order. Looking at your code, we can see:

let mut rdr = Cursor::new(request);
let data_tuple = read_data(&mut rdr).unwrap();

So, data_tuple will be dropped first, while rdr is still alive. This is bad, because rdr must reference the tuple. The easiest fix will be to swap their definitions:

let data_tuple: (u8, u8, Vec<u8>);
let mut rdr = Cursor::new(request);
data_tuple = read_data(&mut rdr).unwrap();

This way, rdr will be dropped first, releasing the reference to data_tuple and letting the tuple be dropped itself.

The "fix" you mentioned works, because every let statement defines new variable, even if the same name is already used, and the existing variable is immediately forgotten. So, when you write:

let mut rdr = Cursor::new(request);
let data_tuple = read_data(&mut rdr).unwrap();
let mut rdr = Cursor::new(data_tuple.2.as_slice());

the second rdr is in no way connected with the first. Essentially, it's almost the same as declaring two different variables, say, rdr and rdr2, and using rdr2 from this place until the end of function.