mod gear;
use crate::hexstr_to_bin;
use crate::ParseFailure;
use gear::GearItem;
use substring::Substring;
macro_rules! assign_or_fail {
($e:expr, $fail:expr) => {
if let Ok(v) = { $e } {
v
} else {
$fail
}
};
}
macro_rules! some_or_fail {
($e:expr, $fail:expr) => {
if let Some(v) = { $e } {
v
} else {
$fail
}
};
}
#[derive(Debug, PartialEq, Eq)]
pub struct S2Loadout {
pub wepset: u32,
pub wepid: u32,
pub head: GearItem,
pub clothes: GearItem,
pub shoes: GearItem,
}
impl std::fmt::Display for S2Loadout {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"0{:x}{:02x}{}{}{}",
self.wepset, self.wepid, self.head, self.clothes, self.shoes
)
}
}
impl std::str::FromStr for S2Loadout {
type Err = ParseFailure;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() != 25 {
return Err(ParseFailure::Length);
}
let version = assign_or_fail!(
u32::from_str_radix(
&some_or_fail!(
hexstr_to_bin(s.substring(0, 1)),
return Err(ParseFailure::Value)
),
2
),
return Err(ParseFailure::Value)
);
if version != 0 {
return Err(ParseFailure::Value);
}
let wepset = assign_or_fail!(
u32::from_str_radix(
&some_or_fail!(
hexstr_to_bin(s.substring(1, 2)),
return Err(ParseFailure::Value)
),
2
),
return Err(ParseFailure::Value)
);
let wepid = assign_or_fail!(
u32::from_str_radix(
&some_or_fail!(
hexstr_to_bin(s.substring(2, 4)),
return Err(ParseFailure::Value)
),
2
),
return Err(ParseFailure::Value)
);
let head = s.substring(4, 11).parse()?;
let clothes = s.substring(11, 18).parse()?;
let shoes = s.substring(18, 25).parse()?;
Ok(S2Loadout {
wepset,
wepid,
head,
clothes,
shoes,
})
}
}
#[cfg(test)]
mod test {
use super::GearItem;
use super::S2Loadout as Loadout;
#[test]
fn forward_back() {
let test_str = "080311694ac62098ce6e214e5";
let res = test_str.parse::<Loadout>().unwrap();
assert_eq!(
res,
Loadout {
wepset: 8,
wepid: 3,
head: GearItem {
id: 17,
main: 13,
subs: [5, 5, 12],
},
clothes: GearItem {
id: 98,
main: 1,
subs: [6, 6, 14],
},
shoes: GearItem {
id: 110,
main: 4,
subs: [5, 7, 5],
},
}
);
let re_encode = res.to_string();
assert_eq!(re_encode, test_str);
}
#[test]
fn identity() {
let test_cases = [
"000c495294a864a4a518c20e6",
"05097d820e64c98000115298c",
"000122294a736a31063ec39ce",
];
for test in &test_cases {
assert_eq!(test, &test.parse::<Loadout>().unwrap().to_string());
}
}
}