0

I have the following Rust struct:

struct Binary<'a> {
    path: PathBuf,
    bytes: Vec<u8>,
    pe: PE<'a>,
}

impl<'a> Binary<'a> {
    fn read(p: PathBuf) -> Binary<'a> {
        todo!();
    }
}

Here PE comes from the goblin crate.

I've tried a few things to implement the read function, but I'm struggling with the dependency between the bytes field and the PE that is referencing those bytes:

For instance:

fn new(p: PathBuf) -> Binary<'a> {
        if let Ok(bytes) = std::fs::read(&p) {
            Binary {
                path: p,
                bytes: bytes,
                pe: PE::parse(&bytes).unwrap()
            }
        } else {
            panic!()
        }
}

Obviously that doesn't work, bytes is borrowed after it has been moved at the bytes: bytes line. I don't see a way to initialize the PE field from the moved value of the bytes field.

Currently I've worked around it by not storing the PE in the Binary struct and simply created a function that returns a PE from the bytes when I need it:

    fn pe(&self) -> Option<PE> {
        match PE::parse(&self.bytes) {
            Ok(p) => Some(p),
            Err(_) => None,
        }
    }

But I'm curious to know what I am missing and how can I parse the file only once.

Jb Evain
  • 17,319
  • 2
  • 67
  • 67

1 Answers1

1

One option is to define the bytes outside of the read function, which works because the lifetime of the bytes is greater than the lifetime of the binary struct.

struct Binary<'a> {
    path: PathBuf,
    bytes: Vec<u8>,
    pe: PE<'a>,
}

impl<'a> Binary<'a> {
    fn read(bytes: &'a [u8], path: PathBuf) -> Result<Self, Box<dyn std::error::Error>> {
        let pe = PE::parse(bytes)?;
        Ok(Self {
            path,
            bytes: bytes.to_vec(),
            pe,
        })
    }
}

fn main() {
    let path = PathBuf::from("my path");
    let bytes = std::fs::read(&path).unwrap();
    let binary = Binary::read(&bytes, path);
}
bencook
  • 21
  • 2