use binrw::{
binread,
io::{Cursor, Seek, SeekFrom},
BinRead,
};
#[test]
fn enum_assert() {
#[derive(BinRead, Debug, PartialEq)]
#[br(assert(b == 1))]
enum Test {
A {
a: u8,
b: u8,
},
#[br(assert(a == -1))]
B {
a: i16,
b: u8,
},
}
assert_eq!(
Test::read_le(&mut Cursor::new(b"\xff\xff\x01")).unwrap(),
Test::B { a: -1, b: 1 }
);
Test::read_le(&mut Cursor::new(b"\xff\xff\0")).expect_err("accepted bad data");
Test::read_le(&mut Cursor::new(b"\0\0\x01")).expect_err("accepted bad data");
}
#[test]
fn enum_assert_with_self() {
#[derive(BinRead, Debug, PartialEq)]
#[br(assert(self.verify()))]
enum Test {
A {
a: u8,
b: u8,
},
#[br(assert(self.verify_only_b()))]
B {
a: i16,
b: u8,
},
}
impl Test {
fn verify(&self) -> bool {
match self {
Test::A { b, .. } => *b == 1,
Test::B { a, b } => *a == -1 && *b == 1,
}
}
fn verify_only_b(&self) -> bool {
matches!(self, Test::B { .. })
}
}
assert_eq!(
Test::read_le(&mut Cursor::new(b"\xff\xff\x01")).unwrap(),
Test::B { a: -1, b: 1 }
);
Test::read_le(&mut Cursor::new(b"\xff\xff\0")).expect_err("accepted bad data");
Test::read_le(&mut Cursor::new(b"\0\0\x01")).expect_err("accepted bad data");
}
#[test]
fn enum_field_args() {
#[derive(BinRead, Debug, PartialEq)]
#[br(import(a: u8))]
struct Foo(#[br(calc(a))] u8);
#[derive(BinRead, Debug, PartialEq)]
#[br(import(a: u8))]
enum Test {
A {
#[br(args(a))]
field: Foo,
},
}
let result = Test::read_le_args(&mut Cursor::new(b""), (42,)).unwrap();
assert_eq!(result, Test::A { field: Foo(42) });
}
#[test]
fn enum_non_copy_args() {
#[derive(BinRead, Debug, PartialEq)]
#[br(import(a: NonCopyArg))]
enum Test {
A {
#[br(calc = a.0)]
a: u8,
},
B {
#[br(calc = a.0)]
_b: u8,
},
}
#[derive(Clone)]
struct NonCopyArg(u8);
let result = Test::read_le_args(&mut Cursor::new(b""), (NonCopyArg(1),)).unwrap();
assert_eq!(result, Test::A { a: 1 });
}
#[test]
fn enum_calc_temp_field() {
#[binread]
#[derive(Debug, Eq, PartialEq)]
enum Test {
#[br(magic(0u8))]
Zero {
#[br(temp)]
a: u8,
#[br(calc(a))]
b: u8,
},
}
let result = Test::read_le(&mut Cursor::new(b"\0\x04")).unwrap();
assert_eq!(result, Test::Zero { b: 4 });
}
#[test]
fn enum_endianness() {
#[derive(BinRead, Debug, Eq, PartialEq)]
#[br(big)]
enum Test {
#[br(magic(1u16))]
OneBig,
#[br(little, magic(2u16))]
TwoLittle {
a: u16,
},
ThreeBig {
a: u16,
b: u16,
c: u16,
},
}
assert_eq!(
Test::read(&mut Cursor::new(b"\0\x01")).unwrap(),
Test::OneBig
);
let error = Test::read(&mut Cursor::new(b"\x01\0")).expect_err("accepted bad data");
assert!(matches!(error, binrw::Error::EnumErrors { .. }));
assert_eq!(
Test::read(&mut Cursor::new(b"\x02\0\x03\0")).unwrap(),
Test::TwoLittle { a: 3 }
);
let error = Test::read(&mut Cursor::new(b"\0\x02\x03\0")).expect_err("accepted bad data");
assert!(matches!(error, binrw::Error::EnumErrors { .. }));
assert_eq!(
Test::read(&mut Cursor::new(b"\0\x03\x01\x00\x02\x00")).unwrap(),
Test::ThreeBig {
a: 3,
b: 0x100,
c: 0x200
}
);
}
#[test]
fn enum_magic() {
#[derive(BinRead, Debug, PartialEq)]
#[br(big, magic(0x1234u16))]
enum Test {
#[br(magic(0u8))]
Zero { a: u16 },
#[br(magic(1u8))]
One { a: u16 },
}
let result = Test::read(&mut Cursor::new(b"\x12\x34\x01\x02\x03")).unwrap();
assert_eq!(result, Test::One { a: 515 });
}
#[test]
fn enum_magic_holey() {
#[derive(BinRead, Debug, PartialEq)]
#[br(big, magic(0x12u8))]
enum Test {
Wrong(#[br(magic(0x01u8))] u16),
#[br(magic(0x12u8))]
Right {
a: u16,
},
}
let result = Test::read(&mut Cursor::new(b"\x12\x12\x01\x02\x03")).unwrap();
assert_eq!(result, Test::Right { a: 0x102 });
}
#[test]
fn enum_pre_assert() {
#[derive(BinRead, Debug, PartialEq)]
#[br(big, import(a: bool))]
enum Test {
#[br(pre_assert(a))]
A(u16),
B(u16),
}
assert_eq!(
Test::read_args(&mut Cursor::new(b"\0\x01"), (true,)).unwrap(),
Test::A(1)
);
assert_eq!(
Test::read_args(&mut Cursor::new(b"\0\x01"), (false,)).unwrap(),
Test::B(1)
);
}
#[test]
fn enum_return_all_errors() {
#[derive(BinRead, Debug)]
#[br(big, return_all_errors)]
enum Test {
#[br(magic(0u16))]
One { _a: u16 },
#[br(magic(1u16))]
Two { _a: u16 },
}
let error = Test::read(&mut Cursor::new("\0\x01")).expect_err("accepted bad data");
match error {
binrw::Error::EnumErrors {
pos,
variant_errors,
} => {
assert_eq!(pos, 0);
assert_eq!(variant_errors.len(), 2);
assert_eq!(variant_errors[0].0, "One");
if let binrw::Error::BadMagic { pos, found } = &variant_errors[0].1 {
assert_eq!(pos, &0);
assert_eq!(&format!("{found:?}"), "1");
} else {
panic!("expected BadMagic; got {:?}", variant_errors[0].1);
}
assert_eq!(variant_errors[1].0, "Two");
assert!(matches!(
variant_errors[1].1.root_cause(),
binrw::Error::Io(..)
));
}
_ => panic!("wrong error type"),
}
}
#[test]
fn enum_rewind_on_assert() {
#[allow(dead_code)]
#[derive(BinRead, Debug)]
#[br(assert(b == 1))]
enum Test {
A { a: u8, b: u8 },
B { a: u16, b: u8 },
}
let mut data = Cursor::new(b"\0\0\0\0");
let expected = data.seek(SeekFrom::Start(1)).unwrap();
Test::read_le(&mut data).expect_err("accepted bad data");
assert_eq!(expected, data.stream_position().unwrap());
}
#[test]
fn enum_rewind_on_eof() {
#[derive(BinRead, Debug)]
enum Test {
A {
_a: u8,
_b: u16,
},
}
let mut data = Cursor::new(b"\0\0\0");
let expected = data.seek(SeekFrom::Start(1)).unwrap();
Test::read_le(&mut data).expect_err("accepted bad data");
assert_eq!(expected, data.stream_position().unwrap());
}
#[test]
fn enum_rewind_on_variant_assert() {
#[allow(dead_code)]
#[derive(BinRead, Debug)]
enum Test {
#[br(assert(b == 1))]
A { a: u8, b: u8 },
}
let mut data = Cursor::new(b"\0\0");
let expected = data.seek(SeekFrom::Start(1)).unwrap();
Test::read_le(&mut data).expect_err("accepted bad data");
assert_eq!(expected, data.stream_position().unwrap());
}
#[test]
fn enum_return_unexpected_error() {
#[derive(BinRead, Debug)]
#[br(big, return_unexpected_error)]
enum Test {
#[br(magic(0u16))]
One { _a: u16 },
#[br(magic(1u16))]
Two { _a: u16 },
}
let error = Test::read(&mut Cursor::new("\0\x01")).expect_err("accepted bad data");
assert!(matches!(error, binrw::Error::NoVariantMatch { .. }));
}
#[test]
fn mixed_enum() {
#[derive(BinRead, Debug, Eq, PartialEq)]
#[br(big)]
enum Test {
#[br(magic(0u8))]
Zero,
#[br(magic(2u8))]
Two { a: u16, b: u16 },
}
assert!(matches!(
Test::read(&mut Cursor::new(b"\0")).unwrap(),
Test::Zero
));
let error = Test::read(&mut Cursor::new(b"\x01")).expect_err("accepted bad data");
assert!(matches!(error, binrw::Error::EnumErrors { .. }));
let result = Test::read(&mut Cursor::new(b"\x02\0\x03\0\x04")).unwrap();
assert_eq!(result, Test::Two { a: 3, b: 4 });
}