infinite-fusion 0.2.0

A simple crate for reading Pokemon Infinite Fusion's data
Documentation
use serde::de::{self, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;

#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct Evolution {
    pub target: EvolutionTarget,
    pub kind: EvolutionKind,
}

#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum EvolutionTarget {
    From { species: String },
    Into { species: String },
}

#[derive(Debug, Clone, Serialize, PartialEq, Eq, strum::EnumDiscriminants)]
#[strum_discriminants(derive(Deserialize), name(EvolutionKindDiscriminant))]
#[serde(rename_all = "snake_case", tag = "type", deny_unknown_fields)]
pub enum EvolutionKind {
    Level { level: u8 },
    Item { item_id: String },
    AttackGreater { level: u8 },
    DefenseGreater { level: u8 },
    HasMove { move_id: String },
    AtkDefEqual { level: u8 },
    DayHoldItem { item_id: String },
    Shedinja { level: u8 },
    Ninjask { level: u8 },
    LevelDay { level: u8 },
    LevelNight { level: u8 },
    Silcoon { level: u8 },
    Cascoon { level: u8 },
    TradeItem { item_id: String },
}

impl<'de> Deserialize<'de> for Evolution {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct EvoVisitor;

        impl<'de> Visitor<'de> for EvoVisitor {
            type Value = Evolution;

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str("[target, kind, parameter, is_devolution]")
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<Evolution, A::Error>
            where
                A: SeqAccess<'de>,
            {
                let species: String = seq
                    .next_element()?
                    .ok_or_else(|| de::Error::custom("missing evolution target"))?;
                let tag: EvolutionKindDiscriminant = seq
                    .next_element()?
                    .ok_or_else(|| de::Error::custom("missing evolution kind"))?;

                let level = |seq: &mut A| -> Result<u8, A::Error> {
                    seq.next_element()?
                        .ok_or_else(|| de::Error::custom("missing level parameter"))
                };
                let item_id = |seq: &mut A| -> Result<String, A::Error> {
                    seq.next_element()?
                        .ok_or_else(|| de::Error::custom("missing item id parameter"))
                };
                let move_id = |seq: &mut A| -> Result<String, A::Error> {
                    seq.next_element()?
                        .ok_or_else(|| de::Error::custom("missing move id parameter"))
                };

                let kind = match tag {
                    EvolutionKindDiscriminant::Level => EvolutionKind::Level {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::LevelDay => EvolutionKind::LevelDay {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::LevelNight => EvolutionKind::LevelNight {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::AttackGreater => EvolutionKind::AttackGreater {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::DefenseGreater => EvolutionKind::DefenseGreater {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::AtkDefEqual => EvolutionKind::AtkDefEqual {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::Shedinja => EvolutionKind::Shedinja {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::Ninjask => EvolutionKind::Ninjask {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::Silcoon => EvolutionKind::Silcoon {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::Cascoon => EvolutionKind::Cascoon {
                        level: level(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::Item => EvolutionKind::Item {
                        item_id: item_id(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::DayHoldItem => EvolutionKind::DayHoldItem {
                        item_id: item_id(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::TradeItem => EvolutionKind::TradeItem {
                        item_id: item_id(&mut seq)?,
                    },
                    EvolutionKindDiscriminant::HasMove => EvolutionKind::HasMove {
                        move_id: move_id(&mut seq)?,
                    },
                };

                let is_devolution: bool = seq
                    .next_element()?
                    .ok_or_else(|| de::Error::custom("missing devolution flag"))?;

                let target = if is_devolution {
                    EvolutionTarget::From { species }
                } else {
                    EvolutionTarget::Into { species }
                };

                Ok(Evolution { target, kind })
            }
        }

        deserializer.deserialize_seq(EvoVisitor)
    }
}