use core::{
fmt,
fmt::Display,
str::FromStr,
};
use anyhow::Error;
use serde::{
Deserialize,
Serialize,
Serializer,
de::{
Unexpected,
Visitor,
},
};
use crate::Type;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OhkoType {
Always,
Type(Type),
}
impl Display for OhkoType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Always => write!(f, "{}", true),
Self::Type(typ) => write!(f, "{typ}"),
}
}
}
impl FromStr for OhkoType {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(OhkoType::Type(Type::from_str(s).map_err(Error::msg)?))
}
}
impl Serialize for OhkoType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::Always => serializer.serialize_bool(true),
Self::Type(typ) => typ.serialize(serializer),
}
}
}
struct OhkoTypeVisitor;
impl<'de> Visitor<'de> for OhkoTypeVisitor {
type Value = OhkoType;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "true or \"level\"")
}
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if !v {
Err(E::invalid_value(Unexpected::Bool(v), &self))
} else {
Ok(Self::Value::Always)
}
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Self::Value::from_str(v).map_err(|_| E::invalid_value(Unexpected::Str(&v), &self))
}
}
impl<'de> Deserialize<'de> for OhkoType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(OhkoTypeVisitor)
}
}
#[cfg(test)]
mod ohko_type_test {
use crate::{
mons::Type,
moves::OhkoType,
test_util::test_serialization,
};
#[test]
fn serializes_to_string() {
test_serialization(OhkoType::Always, true);
test_serialization(OhkoType::Type(Type::Ice), "\"Ice\"");
}
}