binwrite icon indicating copy to clipboard operation
binwrite copied to clipboard

derive macro silently fails when ran on a tuple struct

Open kitlith opened this issue 5 years ago • 1 comments

Apologies, this isn't exactly a minimal test, just how I discovered it.

use binread::{BinRead, NullString};
use binwrite::BinWrite;

// this *compiles* but does not behave as exepected.
#[derive(BinRead, BinWrite, Clone, PartialEq, Default)]
pub struct BadNullString(
    #[binwrite(cstr, preprocessor(NullString::to_string))]
    NullString
);

#[test]
fn test_bad() {
    let test = BadNullString(NullString(Vec::from(&b"Test!"[..])));

    let expected = Vec::from(&b"Test!\0"[..]);

    let mut writer = std::io::Cursor::new(Vec::new());
    test.write(&mut writer).unwrap();

    let res = writer.into_inner();
    assert_eq!(res, expected); // fails, res has no bytes in it
}

// this works correctly
#[derive(BinRead, BinWrite, Clone, PartialEq, Default)]
pub struct GoodNullString {
    #[binwrite(cstr, preprocessor(NullString::to_string))]
    inner: NullString
}

#[test]
fn test_good() {
    let test = GoodNullString { inner: NullString(Vec::from(&b"Test!"[..])) };

    let expected = Vec::from(&b"Test!\0"[..]);

    let mut writer = std::io::Cursor::new(Vec::new());
    test.write(&mut writer).unwrap();

    let res = writer.into_inner();
    assert_eq!(res, expected); // passes
}

kitlith avatar Oct 08 '20 03:10 kitlith

Minimal reproduction:

use binread::{BinRead, NullString};
use binwrite::BinWrite;

#[derive(BinWrite)]
struct Bad(u32);

// #[derive(BinWrite)]
// struct Good {
//     inner: u32
// }

#[test]
fn test_bad() {
    let mut writer = std::io::Cursor::new(Vec::new());
    Bad(0x01020304u32).write(&mut writer);
    // Good {inner: 0x01020304}.write(&mut writer);
    assert_eq!(writer.into_inner(), vec![4, 3, 2, 1]); // fails because no bytes were written!
}

The macro expansion looks like this:

    struct Bad(u32);
    impl ::binwrite::BinWrite for Bad {
        fn write_options<W: ::std::io::Write>(
            &self,
            writer: &mut W,
            options: &::binwrite::WriterOption,
        ) -> ::std::io::Result<()> {
            let mut _writer = ::binwrite::write_track::WriteTrack::new(writer);
            let writer = &mut _writer;
            // note that no writing is occurring here!
            Ok(())
        }
    }

kitlith avatar Oct 08 '20 18:10 kitlith