use crate::as_transparent;
use indexmap::IndexMap;
use reikland::Ignored;
use serde::{Deserialize, Deserializer, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
#[cfg_attr(test, serde(deny_unknown_fields))]
pub struct Ability {
#[serde(rename = "@id")]
pub id: String,
#[serde(rename = "@id_number")]
pub id_number: u8,
#[serde(rename = "@real_name")]
pub real_name: String,
#[serde(rename = "@real_description", deserialize_with = "as_transparent")]
pub real_description: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct AbilityDex(pub Vec<Ability>);
impl<'de> serde::Deserialize<'de> for AbilityDex {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
reikland::DualKeyVec::<(Ability, Ignored)>::deserialize(deserializer)
.map(|reikland::DualKeyVec(mut d)| {
d.sort_by_key(|(a, _)| a.id_number);
d.into_iter().map(|(a, _)| a).collect()
})
.map(AbilityDex)
}
}
#[derive(Debug, Clone, Serialize)]
pub struct AbilityMap(pub IndexMap<String, Ability>);
impl<'de> serde::Deserialize<'de> for AbilityMap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
AbilityDex::deserialize(deserializer)
.map(|AbilityDex(v)| AbilityMap(v.into_iter().map(|a| (a.id.clone(), a)).collect()))
}
}
#[cfg(test)]
mod tests {
use crate::test::PathTracked;
use super::*;
const ABILITIES_DAT: &[u8] = include_bytes!("../InfiniteFusion/Data/abilities.dat");
#[test]
fn deserialize_abilities_dat_vec() {
let PathTracked(dex) = reikland::from_bytes::<PathTracked<AbilityDex>>(ABILITIES_DAT)
.unwrap_or_else(|e| panic!("abilities.dat failed to deserialize: {e}"));
assert!(!dex.0.is_empty());
assert_stench(dex.0.first().unwrap());
}
#[test]
fn deserialize_abilities_dat_map() {
let PathTracked(dex) = reikland::from_bytes::<PathTracked<AbilityMap>>(ABILITIES_DAT)
.unwrap_or_else(|e| panic!("abilities.dat failed to deserialize: {e}"));
assert!(!dex.0.is_empty());
assert_stench(dex.0.first().unwrap().1);
}
fn assert_stench(a: &Ability) {
assert_eq!(a.id, "STENCH");
assert_eq!(a.id_number, 1);
assert_eq!(a.real_name, "Stench");
assert_eq!(
a.real_description,
"The stench may cause the target to flinch."
);
}
}