1use core::fmt::Display;
4use core::num::{NonZeroU16, TryFromIntError};
5use core::str::FromStr;
6
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9use crate::PokemonItem;
10
11#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
29pub struct PokemonItem4(NonZeroU16);
30
31const MAIL_NAMES: [&str; 12] = [
32 "Grass Mail",
33 "Flame Mail",
34 "Bubble Mail",
35 "Bloom Mail",
36 "Tunnel Mail",
37 "Steel Mail",
38 "Heart Mail",
39 "Snow Mail",
40 "Space Mail",
41 "Air Mail",
42 "Mosaic Mail",
43 "Brick Mail",
44];
45
46impl PokemonItem4 {
47 pub fn new(value: u16) -> Option<Self> {
48 Some(Self(NonZeroU16::new(value)?))
49 }
50
51 pub fn new_nonzero(value: NonZeroU16) -> Self {
52 Self(value)
53 }
54
55 pub fn get(self) -> u16 {
57 self.0.get()
58 }
59
60 pub fn get_nonzero(self) -> NonZeroU16 {
62 self.0
63 }
64
65 pub fn valid_dp(self) -> bool {
67 self.0.get() <= 464
68 }
69
70 pub fn valid_platinum(self) -> bool {
72 self.0.get() <= 467
73 }
74
75 pub fn valid_hgss(self) -> bool {
77 self.0.get() <= 536
78 }
79
80 fn index_fixes(val: u16) -> Option<NonZeroU16> {
81 let idx = match val {
82 486 => 487,
84 487 => 486,
85 x => x,
86 };
87 if (137..=148).contains(&idx) || idx > 536 {
88 None
90 } else {
91 NonZeroU16::new(idx)
92 }
93 }
94}
95
96impl From<PokemonItem4> for u16 {
97 fn from(value: PokemonItem4) -> Self {
98 value.0.get()
99 }
100}
101
102impl TryFrom<u16> for PokemonItem4 {
103 type Error = TryFromIntError;
104 fn try_from(value: u16) -> Result<Self, Self::Error> {
105 Ok(Self(NonZeroU16::try_from(value)?))
106 }
107}
108
109impl TryFrom<PokemonItem4> for PokemonItem {
110 type Error = u16;
111 fn try_from(value: PokemonItem4) -> Result<Self, Self::Error> {
115 let val = value.0.get();
116 if let Some(idx) = PokemonItem4::index_fixes(val) {
117 Ok(PokemonItem::from(idx))
118 } else {
119 Err(val)
120 }
121 }
122}
123
124impl TryFrom<PokemonItem> for PokemonItem4 {
125 type Error = u16;
126 fn try_from(value: PokemonItem) -> Result<Self, Self::Error> {
130 let val = value.into();
131 if let Some(idx) = PokemonItem4::index_fixes(val) {
132 Ok(PokemonItem4(idx))
133 } else {
134 Err(val)
135 }
136 }
137}
138
139impl TryFrom<PokemonItem4> for &'static str {
140 type Error = u16;
141 fn try_from(value: PokemonItem4) -> Result<Self, Self::Error> {
142 match value.0.get() {
143 137..=148 => Ok(MAIL_NAMES[value.0.get() as usize - 137]),
144 486 => Ok("Yellow Apricorn"),
145 487 => Ok("Blue Apricorn"),
146 x if x > 536 => Err(x),
147 _ => PokemonItem::from(value.0).try_into(),
148 }
149 }
150}
151
152impl Display for PokemonItem4 {
153 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
154 if let Ok(s) = (*self).try_into() {
155 f.write_str(s)
156 } else {
157 write!(f, "Item {}", self.0.get())
158 }
159 }
160}
161
162impl FromStr for PokemonItem4 {
163 type Err = ();
164 fn from_str(s: &str) -> Result<Self, Self::Err> {
165 for (i, m) in MAIL_NAMES.iter().enumerate() {
166 if s == *m {
167 return Ok(PokemonItem4(NonZeroU16::new(137 + i as u16).unwrap()));
168 }
169 }
170 PokemonItem4::try_from(PokemonItem::from_str(s)?).or(Err(()))
171 }
172}
173
174impl Serialize for PokemonItem4 {
175 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
176 s.collect_str(self)
177 }
178}
179
180impl<'de> Deserialize<'de> for PokemonItem4 {
181 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
182 let s = <&str>::deserialize(d)?;
183 Self::from_str(s).or(Err(serde::de::Error::custom("no match")))
184 }
185}