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)
}
}