1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, strum :: EnumIter)]
3#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4pub enum ArgonIsotope {
6 Ar30,
8 Ar31,
10 Ar32,
12 Ar33,
14 Ar34,
16 Ar35,
18 Ar36,
20 Ar37,
22 Ar38,
24 Ar39,
26 Ar40,
28 Ar41,
30 Ar42,
32 Ar43,
34 Ar44,
36 Ar45,
38 Ar46,
40 Ar47,
42 Ar48,
44 Ar49,
46 Ar50,
48 Ar51,
50 Ar52,
52 Ar53,
54}
55impl super::RelativeAtomicMass for ArgonIsotope {
56 #[inline]
57 fn relative_atomic_mass(&self) -> f64 {
58 match self {
59 Self::Ar30 => 30.02307f64,
60 Self::Ar31 => 31.01212f64,
61 Self::Ar32 => 31.9976378f64,
62 Self::Ar33 => 32.98992555f64,
63 Self::Ar34 => 33.98027009f64,
64 Self::Ar35 => 34.97525759f64,
65 Self::Ar36 => 35.967545105f64,
66 Self::Ar37 => 36.96677633f64,
67 Self::Ar38 => 37.96273211f64,
68 Self::Ar39 => 38.964313f64,
69 Self::Ar40 => 39.9623831237f64,
70 Self::Ar41 => 40.96450057f64,
71 Self::Ar42 => 41.9630457f64,
72 Self::Ar43 => 42.9656361f64,
73 Self::Ar44 => 43.9649238f64,
74 Self::Ar45 => 44.96803973f64,
75 Self::Ar46 => 45.968083f64,
76 Self::Ar47 => 46.972935f64,
77 Self::Ar48 => 47.97591f64,
78 Self::Ar49 => 48.9819f64,
79 Self::Ar50 => 49.98613f64,
80 Self::Ar51 => 50.9937f64,
81 Self::Ar52 => 51.99896f64,
82 Self::Ar53 => 53.00729f64,
83 }
84 }
85}
86impl super::ElementVariant for ArgonIsotope {
87 #[inline]
88 fn element(&self) -> crate::Element {
89 crate::Element::Ar
90 }
91}
92impl super::MassNumber for ArgonIsotope {
93 #[inline]
94 fn mass_number(&self) -> u16 {
95 match self {
96 Self::Ar30 => 30u16,
97 Self::Ar31 => 31u16,
98 Self::Ar32 => 32u16,
99 Self::Ar33 => 33u16,
100 Self::Ar34 => 34u16,
101 Self::Ar35 => 35u16,
102 Self::Ar36 => 36u16,
103 Self::Ar37 => 37u16,
104 Self::Ar38 => 38u16,
105 Self::Ar39 => 39u16,
106 Self::Ar40 => 40u16,
107 Self::Ar41 => 41u16,
108 Self::Ar42 => 42u16,
109 Self::Ar43 => 43u16,
110 Self::Ar44 => 44u16,
111 Self::Ar45 => 45u16,
112 Self::Ar46 => 46u16,
113 Self::Ar47 => 47u16,
114 Self::Ar48 => 48u16,
115 Self::Ar49 => 49u16,
116 Self::Ar50 => 50u16,
117 Self::Ar51 => 51u16,
118 Self::Ar52 => 52u16,
119 Self::Ar53 => 53u16,
120 }
121 }
122}
123impl super::IsotopicComposition for ArgonIsotope {
124 #[inline]
125 fn isotopic_composition(&self) -> Option<f64> {
126 match self {
127 Self::Ar36 => Some(0.003336f64),
128 Self::Ar38 => Some(0.000629f64),
129 Self::Ar40 => Some(0.996035f64),
130 _ => None,
131 }
132 }
133}
134impl super::MostAbundantIsotope for ArgonIsotope {
135 fn most_abundant_isotope() -> Self {
136 Self::Ar40
137 }
138}
139impl From<ArgonIsotope> for crate::Isotope {
140 fn from(isotope: ArgonIsotope) -> Self {
141 crate::Isotope::Ar(isotope)
142 }
143}
144impl From<ArgonIsotope> for crate::Element {
145 fn from(_isotope: ArgonIsotope) -> Self {
146 crate::Element::Ar
147 }
148}
149impl TryFrom<u64> for ArgonIsotope {
150 type Error = crate::errors::Error;
151 fn try_from(value: u64) -> Result<Self, Self::Error> {
152 match value {
153 30u64 => Ok(Self::Ar30),
154 31u64 => Ok(Self::Ar31),
155 32u64 => Ok(Self::Ar32),
156 33u64 => Ok(Self::Ar33),
157 34u64 => Ok(Self::Ar34),
158 35u64 => Ok(Self::Ar35),
159 36u64 => Ok(Self::Ar36),
160 37u64 => Ok(Self::Ar37),
161 38u64 => Ok(Self::Ar38),
162 39u64 => Ok(Self::Ar39),
163 40u64 => Ok(Self::Ar40),
164 41u64 => Ok(Self::Ar41),
165 42u64 => Ok(Self::Ar42),
166 43u64 => Ok(Self::Ar43),
167 44u64 => Ok(Self::Ar44),
168 45u64 => Ok(Self::Ar45),
169 46u64 => Ok(Self::Ar46),
170 47u64 => Ok(Self::Ar47),
171 48u64 => Ok(Self::Ar48),
172 49u64 => Ok(Self::Ar49),
173 50u64 => Ok(Self::Ar50),
174 51u64 => Ok(Self::Ar51),
175 52u64 => Ok(Self::Ar52),
176 53u64 => Ok(Self::Ar53),
177 _ => Err(crate::errors::Error::Isotope(crate::Element::Ar, value)),
178 }
179 }
180}
181impl TryFrom<u8> for ArgonIsotope {
182 type Error = crate::errors::Error;
183 fn try_from(value: u8) -> Result<Self, Self::Error> {
184 Self::try_from(u64::from(value))
185 }
186}
187impl TryFrom<u16> for ArgonIsotope {
188 type Error = crate::errors::Error;
189 fn try_from(value: u16) -> Result<Self, Self::Error> {
190 Self::try_from(u64::from(value))
191 }
192}
193impl TryFrom<u32> for ArgonIsotope {
194 type Error = crate::errors::Error;
195 fn try_from(value: u32) -> Result<Self, Self::Error> {
196 Self::try_from(u64::from(value))
197 }
198}
199impl core::fmt::Display for ArgonIsotope {
200 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
201 match self {
202 Self::Ar30 => write!(f, "Ar30"),
203 Self::Ar31 => write!(f, "Ar31"),
204 Self::Ar32 => write!(f, "Ar32"),
205 Self::Ar33 => write!(f, "Ar33"),
206 Self::Ar34 => write!(f, "Ar34"),
207 Self::Ar35 => write!(f, "Ar35"),
208 Self::Ar36 => write!(f, "Ar36"),
209 Self::Ar37 => write!(f, "Ar37"),
210 Self::Ar38 => write!(f, "Ar38"),
211 Self::Ar39 => write!(f, "Ar39"),
212 Self::Ar40 => write!(f, "Ar40"),
213 Self::Ar41 => write!(f, "Ar41"),
214 Self::Ar42 => write!(f, "Ar42"),
215 Self::Ar43 => write!(f, "Ar43"),
216 Self::Ar44 => write!(f, "Ar44"),
217 Self::Ar45 => write!(f, "Ar45"),
218 Self::Ar46 => write!(f, "Ar46"),
219 Self::Ar47 => write!(f, "Ar47"),
220 Self::Ar48 => write!(f, "Ar48"),
221 Self::Ar49 => write!(f, "Ar49"),
222 Self::Ar50 => write!(f, "Ar50"),
223 Self::Ar51 => write!(f, "Ar51"),
224 Self::Ar52 => write!(f, "Ar52"),
225 Self::Ar53 => write!(f, "Ar53"),
226 }
227 }
228}
229#[cfg(test)]
230mod tests {
231 use strum::IntoEnumIterator;
232
233 use super::*;
234 use crate::isotopes::{
235 ElementVariant, IsotopicComposition, MassNumber, MostAbundantIsotope, RelativeAtomicMass,
236 };
237 #[test]
238 fn test_relative_atomic_mass() {
239 for isotope in ArgonIsotope::iter() {
240 let mass = isotope.relative_atomic_mass();
241 assert!(mass > 0.0, "Mass should be positive for {isotope:?}");
242 }
243 }
244 #[test]
245 fn test_element() {
246 for isotope in ArgonIsotope::iter() {
247 let element = isotope.element();
248 assert_eq!(element, crate::Element::Ar, "Element should be correct for {isotope:?}");
249 }
250 }
251 #[test]
252 fn test_mass_number() {
253 for isotope in ArgonIsotope::iter() {
254 let mass_number = isotope.mass_number();
255 assert!(
256 mass_number > 0 && mass_number < 300,
257 "Mass number should be reasonable for {isotope:?}"
258 );
259 }
260 }
261 #[test]
262 fn test_isotopic_composition() {
263 for isotope in ArgonIsotope::iter() {
264 let comp = isotope.isotopic_composition();
265 if let Some(c) = comp {
266 assert!(
267 (0.0..=1.0).contains(&c),
268 "Composition should be between 0 and 1 for {isotope:?}"
269 );
270 }
271 }
272 }
273 #[test]
274 fn test_most_abundant() {
275 let most_abundant = ArgonIsotope::most_abundant_isotope();
276 let _ = most_abundant.relative_atomic_mass();
277 }
278 #[test]
279 fn test_from_isotope() {
280 for isotope in ArgonIsotope::iter() {
281 let iso: crate::Isotope = isotope.into();
282 match iso {
283 crate::Isotope::Ar(i) => assert_eq!(i, isotope),
284 _ => panic!("Wrong isotope type"),
285 }
286 }
287 }
288 #[test]
289 fn test_from_element() {
290 for isotope in ArgonIsotope::iter() {
291 let elem: crate::Element = isotope.into();
292 assert_eq!(elem, crate::Element::Ar);
293 }
294 }
295 #[test]
296 fn test_try_from_mass_number() {
297 for isotope in ArgonIsotope::iter() {
298 let mass = isotope.mass_number();
299 let iso = ArgonIsotope::try_from(mass).unwrap();
300 assert_eq!(iso, isotope);
301 let iso_u32 = ArgonIsotope::try_from(u32::from(mass)).unwrap();
302 assert_eq!(iso_u32, isotope);
303 if let Ok(mass_u8) = u8::try_from(mass) {
304 let iso_u8 = ArgonIsotope::try_from(mass_u8).unwrap();
305 assert_eq!(iso_u8, isotope);
306 }
307 }
308 assert!(ArgonIsotope::try_from(0_u16).is_err());
309 assert!(ArgonIsotope::try_from(1000_u16).is_err());
310 assert!(ArgonIsotope::try_from(0_u32).is_err());
311 assert!(ArgonIsotope::try_from(1000_u32).is_err());
312 assert!(ArgonIsotope::try_from(0_u8).is_err());
313 }
314 #[test]
315 fn test_display() {
316 for isotope in ArgonIsotope::iter() {
317 let s = alloc::format!("{isotope}");
318 assert!(!s.is_empty(), "Display should not be empty for {isotope:?}");
319 }
320 }
321}