Skip to main content

battler_data/moves/
switch_type.rs

1use alloc::format;
2use core::{
3    fmt,
4    fmt::Display,
5    str::FromStr,
6};
7
8use anyhow::Error;
9use serde::{
10    Deserialize,
11    Serialize,
12    Serializer,
13    de::{
14        Unexpected,
15        Visitor,
16    },
17};
18
19/// The type of user switch performed when using a move.
20#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
21pub enum SwitchType {
22    /// Normal switch out.
23    #[default]
24    Normal,
25    /// Switch out that copies all volatile effects to the replacement Mon.
26    CopyVolatile,
27    /// Normal switch out if the move hit.
28    IfHit,
29}
30
31impl SwitchType {
32    /// Does the switch depend on hitting the target?
33    pub fn if_hit(&self) -> bool {
34        match self {
35            Self::IfHit => true,
36            _ => false,
37        }
38    }
39}
40
41impl Display for SwitchType {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            Self::Normal => write!(f, "{}", true),
45            Self::CopyVolatile => write!(f, "copyvolatile"),
46            Self::IfHit => write!(f, "ifhit"),
47        }
48    }
49}
50
51impl FromStr for SwitchType {
52    type Err = Error;
53    fn from_str(s: &str) -> Result<Self, Self::Err> {
54        match s {
55            "copyvolatile" => Ok(Self::CopyVolatile),
56            "ifhit" => Ok(Self::IfHit),
57            _ => Err(Error::msg(format!("invalid user switch type: \"{s}\""))),
58        }
59    }
60}
61
62impl Serialize for SwitchType {
63    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
64    where
65        S: Serializer,
66    {
67        match self {
68            Self::Normal => serializer.serialize_bool(true),
69            Self::CopyVolatile => serializer.serialize_str("copyvolatile"),
70            Self::IfHit => serializer.serialize_str("ifhit"),
71        }
72    }
73}
74
75struct UserSwitchTypeVisitor;
76
77impl<'de> Visitor<'de> for UserSwitchTypeVisitor {
78    type Value = SwitchType;
79
80    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
81        write!(formatter, "true, \"copyvolatile\", or \"ifhit\"")
82    }
83
84    fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
85    where
86        E: serde::de::Error,
87    {
88        if !v {
89            Err(E::invalid_value(Unexpected::Bool(v), &self))
90        } else {
91            Ok(Self::Value::Normal)
92        }
93    }
94
95    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
96    where
97        E: serde::de::Error,
98    {
99        Self::Value::from_str(v).map_err(|_| E::invalid_value(Unexpected::Str(&v), &self))
100    }
101}
102
103impl<'de> Deserialize<'de> for SwitchType {
104    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
105    where
106        D: serde::Deserializer<'de>,
107    {
108        deserializer.deserialize_any(UserSwitchTypeVisitor)
109    }
110}
111
112#[cfg(test)]
113mod user_switch_type_test {
114    use crate::{
115        moves::SwitchType,
116        test_util::test_serialization,
117    };
118
119    #[test]
120    fn serializes_to_string() {
121        test_serialization(SwitchType::Normal, true);
122        test_serialization(SwitchType::CopyVolatile, "\"copyvolatile\"");
123        test_serialization(SwitchType::IfHit, "\"ifhit\"");
124    }
125}