jam1garner / binrw

A Rust crate for helping parse and rebuild binary data using ✨macro magic✨.
https://binrw.rs
MIT License
545 stars 35 forks source link

Custom error does not propagate for nested data types #228

Closed wangbj closed 9 months ago

wangbj commented 9 months ago

Given below example:

#![allow(dead_code)]
use std::io;
use std::fmt;
use binrw::BinRead;

#[derive(Clone, Copy, Debug)]
#[repr(u32)]
enum Error {
  Failed = 1,
}

impl std::error::Error for Error {}

impl fmt::Display for Error {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "Error::Failed")
  }
}

#[derive(BinRead, Debug)]
struct MyStruct {
  #[br(assert(version != 0, Error::Failed))]
  version: u32,
}

#[derive(BinRead, Debug)]
struct SizedStruct {
  size: u32,
  inner: MyStruct,
}

fn main() -> anyhow::Result<()> {
  let mut buf = io::Cursor::new(vec![0u8; 8]);
  let s: SizedStruct = BinRead::read_ne(&mut buf).map_err(|err| {
    assert!(err.custom_err::<Error>().is_some());
    err
  })?;

  println!("s = {:?}", s);
  Ok(())
}

The code would fail at assertion failure, because the error type is not a custom_err, with the assert removed, it will print:

Error: 
 ╺━━━━━━━━━━━━━━━━━━━━┅ Backtrace ┅━━━━━━━━━━━━━━━━━━━━╸

 0: Error: Error::Failed at 0x4
           While parsing field 'inner' in SizedStruct
     at src/main.rs:29

 ╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸

Which is a backtrace error, or binrw::error::Error::Backtrace(_) to be precise; while I was expecting binrw::error::Error:: Custom instead. Notice if I call read_ne on MyStruct the function could indeed return custom error, which is inconsistent, hence I feel like this is a bug in binrw.