use binrw::{BinRead, BinResult, Endian};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ApplyOptionKind {
IgnoreMissing,
IgnoreOldMismatch,
}
fn read_apply_option_kind<R: std::io::Read + std::io::Seek>(
reader: &mut R,
endian: Endian,
(): (),
) -> BinResult<ApplyOptionKind> {
let raw = <u32 as BinRead>::read_options(reader, endian, ())?;
match raw {
1 => Ok(ApplyOptionKind::IgnoreMissing),
2 => Ok(ApplyOptionKind::IgnoreOldMismatch),
_ => Err(binrw::Error::Custom {
pos: 0,
err: Box::new(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"unknown ApplyOption kind",
)),
}),
}
}
#[derive(BinRead, Debug, Clone, PartialEq, Eq)]
#[br(big)]
pub struct ApplyOption {
#[br(parse_with = read_apply_option_kind)]
pub kind: ApplyOptionKind,
#[br(pad_before = 4, map = |x: u32| x != 0)]
pub value: bool,
}
pub(crate) fn parse(body: &[u8]) -> crate::Result<ApplyOption> {
super::util::parse_be(body)
}
#[cfg(test)]
mod tests {
use super::*;
fn make_body(kind: u32, value: u32) -> Vec<u8> {
let mut body = Vec::new();
body.extend_from_slice(&kind.to_be_bytes());
body.extend_from_slice(&[0u8; 4]); body.extend_from_slice(&value.to_be_bytes());
body
}
#[test]
fn parses_apply_option_ignore_missing() {
let cmd = parse(&make_body(1, 0)).unwrap();
assert_eq!(cmd.kind, ApplyOptionKind::IgnoreMissing);
assert!(!cmd.value);
}
#[test]
fn parses_apply_option_ignore_old_mismatch() {
let cmd = parse(&make_body(2, 1)).unwrap();
assert_eq!(cmd.kind, ApplyOptionKind::IgnoreOldMismatch);
assert!(cmd.value);
}
#[test]
fn rejects_invalid_apply_option_kind() {
assert!(parse(&make_body(0, 0)).is_err());
assert!(parse(&make_body(3, 0)).is_err());
}
}