1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, strum :: EnumIter)]
3#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4pub enum MagnesiumIsotope {
6 Mg19,
8 Mg20,
10 Mg21,
12 Mg22,
14 Mg23,
16 Mg24,
18 Mg25,
20 Mg26,
22 Mg27,
24 Mg28,
26 Mg29,
28 Mg30,
30 Mg31,
32 Mg32,
34 Mg33,
36 Mg34,
38 Mg35,
40 Mg36,
42 Mg37,
44 Mg38,
46 Mg39,
48 Mg40,
50}
51impl super::RelativeAtomicMass for MagnesiumIsotope {
52 #[inline]
53 fn relative_atomic_mass(&self) -> f64 {
54 match self {
55 Self::Mg19 => 19.034169f64,
56 Self::Mg20 => 20.01885f64,
57 Self::Mg21 => 21.011716f64,
58 Self::Mg22 => 21.99957065f64,
59 Self::Mg23 => 22.99412421f64,
60 Self::Mg24 => 23.985041697f64,
61 Self::Mg25 => 24.985836976f64,
62 Self::Mg26 => 25.982592968f64,
63 Self::Mg27 => 26.984340624f64,
64 Self::Mg28 => 27.9838767f64,
65 Self::Mg29 => 28.988617f64,
66 Self::Mg30 => 29.9904629f64,
67 Self::Mg31 => 30.996648f64,
68 Self::Mg32 => 31.9991102f64,
69 Self::Mg33 => 33.0053271f64,
70 Self::Mg34 => 34.008935f64,
71 Self::Mg35 => 35.01679f64,
72 Self::Mg36 => 36.02188f64,
73 Self::Mg37 => 37.03037f64,
74 Self::Mg38 => 38.03658f64,
75 Self::Mg39 => 39.04538f64,
76 Self::Mg40 => 40.05218f64,
77 }
78 }
79}
80impl super::ElementVariant for MagnesiumIsotope {
81 #[inline]
82 fn element(&self) -> crate::Element {
83 crate::Element::Mg
84 }
85}
86impl super::MassNumber for MagnesiumIsotope {
87 #[inline]
88 fn mass_number(&self) -> u16 {
89 match self {
90 Self::Mg19 => 19u16,
91 Self::Mg20 => 20u16,
92 Self::Mg21 => 21u16,
93 Self::Mg22 => 22u16,
94 Self::Mg23 => 23u16,
95 Self::Mg24 => 24u16,
96 Self::Mg25 => 25u16,
97 Self::Mg26 => 26u16,
98 Self::Mg27 => 27u16,
99 Self::Mg28 => 28u16,
100 Self::Mg29 => 29u16,
101 Self::Mg30 => 30u16,
102 Self::Mg31 => 31u16,
103 Self::Mg32 => 32u16,
104 Self::Mg33 => 33u16,
105 Self::Mg34 => 34u16,
106 Self::Mg35 => 35u16,
107 Self::Mg36 => 36u16,
108 Self::Mg37 => 37u16,
109 Self::Mg38 => 38u16,
110 Self::Mg39 => 39u16,
111 Self::Mg40 => 40u16,
112 }
113 }
114}
115impl super::IsotopicComposition for MagnesiumIsotope {
116 #[inline]
117 fn isotopic_composition(&self) -> Option<f64> {
118 match self {
119 Self::Mg24 => Some(0.7899f64),
120 Self::Mg25 => Some(0.1f64),
121 Self::Mg26 => Some(0.1101f64),
122 _ => None,
123 }
124 }
125}
126impl super::MostAbundantIsotope for MagnesiumIsotope {
127 fn most_abundant_isotope() -> Self {
128 Self::Mg24
129 }
130}
131impl From<MagnesiumIsotope> for crate::Isotope {
132 fn from(isotope: MagnesiumIsotope) -> Self {
133 crate::Isotope::Mg(isotope)
134 }
135}
136impl From<MagnesiumIsotope> for crate::Element {
137 fn from(_isotope: MagnesiumIsotope) -> Self {
138 crate::Element::Mg
139 }
140}
141impl TryFrom<u64> for MagnesiumIsotope {
142 type Error = crate::errors::Error;
143 fn try_from(value: u64) -> Result<Self, Self::Error> {
144 match value {
145 19u64 => Ok(Self::Mg19),
146 20u64 => Ok(Self::Mg20),
147 21u64 => Ok(Self::Mg21),
148 22u64 => Ok(Self::Mg22),
149 23u64 => Ok(Self::Mg23),
150 24u64 => Ok(Self::Mg24),
151 25u64 => Ok(Self::Mg25),
152 26u64 => Ok(Self::Mg26),
153 27u64 => Ok(Self::Mg27),
154 28u64 => Ok(Self::Mg28),
155 29u64 => Ok(Self::Mg29),
156 30u64 => Ok(Self::Mg30),
157 31u64 => Ok(Self::Mg31),
158 32u64 => Ok(Self::Mg32),
159 33u64 => Ok(Self::Mg33),
160 34u64 => Ok(Self::Mg34),
161 35u64 => Ok(Self::Mg35),
162 36u64 => Ok(Self::Mg36),
163 37u64 => Ok(Self::Mg37),
164 38u64 => Ok(Self::Mg38),
165 39u64 => Ok(Self::Mg39),
166 40u64 => Ok(Self::Mg40),
167 _ => Err(crate::errors::Error::Isotope(crate::Element::Mg, value)),
168 }
169 }
170}
171impl TryFrom<u8> for MagnesiumIsotope {
172 type Error = crate::errors::Error;
173 fn try_from(value: u8) -> Result<Self, Self::Error> {
174 Self::try_from(u64::from(value))
175 }
176}
177impl TryFrom<u16> for MagnesiumIsotope {
178 type Error = crate::errors::Error;
179 fn try_from(value: u16) -> Result<Self, Self::Error> {
180 Self::try_from(u64::from(value))
181 }
182}
183impl TryFrom<u32> for MagnesiumIsotope {
184 type Error = crate::errors::Error;
185 fn try_from(value: u32) -> Result<Self, Self::Error> {
186 Self::try_from(u64::from(value))
187 }
188}
189impl core::fmt::Display for MagnesiumIsotope {
190 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
191 match self {
192 Self::Mg19 => write!(f, "Mg19"),
193 Self::Mg20 => write!(f, "Mg20"),
194 Self::Mg21 => write!(f, "Mg21"),
195 Self::Mg22 => write!(f, "Mg22"),
196 Self::Mg23 => write!(f, "Mg23"),
197 Self::Mg24 => write!(f, "Mg24"),
198 Self::Mg25 => write!(f, "Mg25"),
199 Self::Mg26 => write!(f, "Mg26"),
200 Self::Mg27 => write!(f, "Mg27"),
201 Self::Mg28 => write!(f, "Mg28"),
202 Self::Mg29 => write!(f, "Mg29"),
203 Self::Mg30 => write!(f, "Mg30"),
204 Self::Mg31 => write!(f, "Mg31"),
205 Self::Mg32 => write!(f, "Mg32"),
206 Self::Mg33 => write!(f, "Mg33"),
207 Self::Mg34 => write!(f, "Mg34"),
208 Self::Mg35 => write!(f, "Mg35"),
209 Self::Mg36 => write!(f, "Mg36"),
210 Self::Mg37 => write!(f, "Mg37"),
211 Self::Mg38 => write!(f, "Mg38"),
212 Self::Mg39 => write!(f, "Mg39"),
213 Self::Mg40 => write!(f, "Mg40"),
214 }
215 }
216}
217#[cfg(test)]
218mod tests {
219 use strum::IntoEnumIterator;
220
221 use super::*;
222 use crate::isotopes::{
223 ElementVariant, IsotopicComposition, MassNumber, MostAbundantIsotope, RelativeAtomicMass,
224 };
225 #[test]
226 fn test_relative_atomic_mass() {
227 for isotope in MagnesiumIsotope::iter() {
228 let mass = isotope.relative_atomic_mass();
229 assert!(mass > 0.0, "Mass should be positive for {isotope:?}");
230 }
231 }
232 #[test]
233 fn test_element() {
234 for isotope in MagnesiumIsotope::iter() {
235 let element = isotope.element();
236 assert_eq!(element, crate::Element::Mg, "Element should be correct for {isotope:?}");
237 }
238 }
239 #[test]
240 fn test_mass_number() {
241 for isotope in MagnesiumIsotope::iter() {
242 let mass_number = isotope.mass_number();
243 assert!(
244 mass_number > 0 && mass_number < 300,
245 "Mass number should be reasonable for {isotope:?}"
246 );
247 }
248 }
249 #[test]
250 fn test_isotopic_composition() {
251 for isotope in MagnesiumIsotope::iter() {
252 let comp = isotope.isotopic_composition();
253 if let Some(c) = comp {
254 assert!(
255 (0.0..=1.0).contains(&c),
256 "Composition should be between 0 and 1 for {isotope:?}"
257 );
258 }
259 }
260 }
261 #[test]
262 fn test_most_abundant() {
263 let most_abundant = MagnesiumIsotope::most_abundant_isotope();
264 let _ = most_abundant.relative_atomic_mass();
265 }
266 #[test]
267 fn test_from_isotope() {
268 for isotope in MagnesiumIsotope::iter() {
269 let iso: crate::Isotope = isotope.into();
270 match iso {
271 crate::Isotope::Mg(i) => assert_eq!(i, isotope),
272 _ => panic!("Wrong isotope type"),
273 }
274 }
275 }
276 #[test]
277 fn test_from_element() {
278 for isotope in MagnesiumIsotope::iter() {
279 let elem: crate::Element = isotope.into();
280 assert_eq!(elem, crate::Element::Mg);
281 }
282 }
283 #[test]
284 fn test_try_from_mass_number() {
285 for isotope in MagnesiumIsotope::iter() {
286 let mass = isotope.mass_number();
287 let iso = MagnesiumIsotope::try_from(mass).unwrap();
288 assert_eq!(iso, isotope);
289 let iso_u32 = MagnesiumIsotope::try_from(u32::from(mass)).unwrap();
290 assert_eq!(iso_u32, isotope);
291 if let Ok(mass_u8) = u8::try_from(mass) {
292 let iso_u8 = MagnesiumIsotope::try_from(mass_u8).unwrap();
293 assert_eq!(iso_u8, isotope);
294 }
295 }
296 assert!(MagnesiumIsotope::try_from(0_u16).is_err());
297 assert!(MagnesiumIsotope::try_from(1000_u16).is_err());
298 assert!(MagnesiumIsotope::try_from(0_u32).is_err());
299 assert!(MagnesiumIsotope::try_from(1000_u32).is_err());
300 assert!(MagnesiumIsotope::try_from(0_u8).is_err());
301 }
302 #[test]
303 fn test_display() {
304 for isotope in MagnesiumIsotope::iter() {
305 let s = alloc::format!("{isotope}");
306 assert!(!s.is_empty(), "Display should not be empty for {isotope:?}");
307 }
308 }
309}