Skip to main content

battler_data/moves/
accuracy.rs

1use alloc::format;
2use core::{
3    fmt,
4    str::FromStr,
5};
6
7use anyhow::Error;
8use serde::{
9    Deserialize,
10    Serialize,
11    Serializer,
12    de::Visitor,
13};
14
15/// The base accuracy of a move.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum Accuracy {
18    /// The base chance for the move to hit.
19    Chance(u8),
20    /// The move is exempt from accuracy checks.
21    Exempt,
22}
23
24impl Accuracy {
25    pub fn percentage(&self) -> Option<u8> {
26        match self {
27            Self::Chance(n) => Some(*n),
28            Self::Exempt => None,
29        }
30    }
31}
32
33impl Default for Accuracy {
34    fn default() -> Self {
35        Self::Chance(100)
36    }
37}
38
39impl From<u8> for Accuracy {
40    fn from(value: u8) -> Self {
41        Self::Chance(value)
42    }
43}
44
45impl FromStr for Accuracy {
46    type Err = Error;
47
48    fn from_str(s: &str) -> Result<Self, Self::Err> {
49        match s {
50            "exempt" => Ok(Self::Exempt),
51            _ => Err(Error::msg(format!("invalid accuracy \"{s}\""))),
52        }
53    }
54}
55
56impl Serialize for Accuracy {
57    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58    where
59        S: Serializer,
60    {
61        match self {
62            Self::Chance(n) => serializer.serialize_u8(*n),
63            Self::Exempt => serializer.collect_str("exempt"),
64        }
65    }
66}
67
68struct AccuracyVisitor;
69
70impl<'de> Visitor<'de> for AccuracyVisitor {
71    type Value = Accuracy;
72
73    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
74        write!(formatter, "an integer or \"exempt\"")
75    }
76
77    fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
78    where
79        E: serde::de::Error,
80    {
81        Ok(Self::Value::from(v))
82    }
83
84    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
85    where
86        E: serde::de::Error,
87    {
88        Ok(Self::Value::from(v as u8))
89    }
90
91    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
92    where
93        E: serde::de::Error,
94    {
95        Self::Value::from_str(v)
96            .map_err(|_| E::invalid_value(serde::de::Unexpected::Str(&v), &self))
97    }
98}
99
100impl<'de> Deserialize<'de> for Accuracy {
101    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
102    where
103        D: serde::Deserializer<'de>,
104    {
105        deserializer.deserialize_any(AccuracyVisitor)
106    }
107}
108
109#[cfg(test)]
110mod accuracy_test {
111    use crate::{
112        moves::Accuracy,
113        test_util::test_serialization,
114    };
115
116    #[test]
117    fn serializes_numbers_and_strings() {
118        test_serialization(Accuracy::Chance(100), 100);
119        test_serialization(Accuracy::Chance(50), 50);
120        test_serialization(Accuracy::Exempt, "\"exempt\"");
121    }
122}