sharksforarms / deku

Declarative binary reading and writing: bit-level, symmetric, serialization/deserialization
Apache License 2.0
1.14k stars 55 forks source link

How to consume bytes when parsing? #299

Closed duskmoon314 closed 1 year ago

duskmoon314 commented 1 year ago

I'm trying to wrap from_bytes in a TryFrom implementation and coming across the issue of cannot return value referencing local variable. It seems from_bytes borrow the variable instead of consuming it.

More specifically, I have a base64 encoded string in struct O and a struct S (which might be too complicated to describe here), which needs to be parsed from the encoded string. My idea is to implement a TryFrom<O> for S like this:

impl TryFrom<O> for S<'_> {
    type Error = MyError;

    fn try_from(origin: O) -> Result<Self, MyError> {
        let (_, target)= S::from_bytes((&base64::decod(origin.encoded_string)?, 0))?;
        Ok(target)
    }
}

But this borrows the origin and cannot return. Thus I try this:

let s1: Vec<u8> = base64::decode(&origin.encoded_string)?;

let (_, s2) = S::from_bytes((&s1, 0))?;
//                            -- borrow of `s1` occurs here

drop(s1);
//   ^^ move out of `s1` occurs here

println!("{:?}", s2);
//               -- borrow later used here

I want to have a way to consume the original slice of bytes and return the result after parsing. How can I achieve this?

duskmoon314 commented 1 year ago

It seems the problem happens in the struct S, which uses map during deku's parsing. I will keep digging out what happens

duskmoon314 commented 1 year ago

It turns out a field inside S, which has the type of another crate, keeps the reference and causes this issue. Sorry for bothering.

sharksforarms commented 1 year ago

There is also TryFrom which gets implemented as part of the DekuRead derive, S::try_from(&s1)