elements_rs/isotopes/
hydrogen.rs

1//! Isotopes of the element Hydrogen
2#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, strum :: EnumIter)]
3#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4/// Isotopes of the element Hydrogen
5pub enum HydrogenIsotope {
6    /// Isotope H1 of Hydrogen
7    H1,
8    /// Isotope D of Hydrogen
9    D,
10    /// Isotope T of Hydrogen
11    T,
12    /// Isotope H4 of Hydrogen
13    H4,
14    /// Isotope H5 of Hydrogen
15    H5,
16    /// Isotope H6 of Hydrogen
17    H6,
18    /// Isotope H7 of Hydrogen
19    H7,
20}
21impl super::RelativeAtomicMass for HydrogenIsotope {
22    #[inline]
23    fn relative_atomic_mass(&self) -> f64 {
24        match self {
25            Self::H1 => 1.00782503223f64,
26            Self::D => 2.01410177812f64,
27            Self::T => 3.0160492779f64,
28            Self::H4 => 4.02643f64,
29            Self::H5 => 5.035311f64,
30            Self::H6 => 6.04496f64,
31            Self::H7 => 7.0527f64,
32        }
33    }
34}
35impl super::ElementVariant for HydrogenIsotope {
36    #[inline]
37    fn element(&self) -> crate::Element {
38        crate::Element::H
39    }
40}
41impl super::MassNumber for HydrogenIsotope {
42    #[inline]
43    fn mass_number(&self) -> u16 {
44        match self {
45            Self::H1 => 1u16,
46            Self::D => 2u16,
47            Self::T => 3u16,
48            Self::H4 => 4u16,
49            Self::H5 => 5u16,
50            Self::H6 => 6u16,
51            Self::H7 => 7u16,
52        }
53    }
54}
55impl super::IsotopicComposition for HydrogenIsotope {
56    #[inline]
57    fn isotopic_composition(&self) -> Option<f64> {
58        match self {
59            Self::H1 => Some(0.999885f64),
60            Self::D => Some(0.000115f64),
61            _ => None,
62        }
63    }
64}
65impl super::MostAbundantIsotope for HydrogenIsotope {
66    fn most_abundant_isotope() -> Self {
67        Self::H1
68    }
69}
70impl From<HydrogenIsotope> for crate::Isotope {
71    fn from(isotope: HydrogenIsotope) -> Self {
72        crate::Isotope::H(isotope)
73    }
74}
75impl From<HydrogenIsotope> for crate::Element {
76    fn from(_isotope: HydrogenIsotope) -> Self {
77        crate::Element::H
78    }
79}
80impl TryFrom<u64> for HydrogenIsotope {
81    type Error = crate::errors::Error;
82    fn try_from(value: u64) -> Result<Self, Self::Error> {
83        match value {
84            1u64 => Ok(Self::H1),
85            2u64 => Ok(Self::D),
86            3u64 => Ok(Self::T),
87            4u64 => Ok(Self::H4),
88            5u64 => Ok(Self::H5),
89            6u64 => Ok(Self::H6),
90            7u64 => Ok(Self::H7),
91            _ => Err(crate::errors::Error::Isotope(crate::Element::H, value)),
92        }
93    }
94}
95impl TryFrom<u8> for HydrogenIsotope {
96    type Error = crate::errors::Error;
97    fn try_from(value: u8) -> Result<Self, Self::Error> {
98        Self::try_from(u64::from(value))
99    }
100}
101impl TryFrom<u16> for HydrogenIsotope {
102    type Error = crate::errors::Error;
103    fn try_from(value: u16) -> Result<Self, Self::Error> {
104        Self::try_from(u64::from(value))
105    }
106}
107impl TryFrom<u32> for HydrogenIsotope {
108    type Error = crate::errors::Error;
109    fn try_from(value: u32) -> Result<Self, Self::Error> {
110        Self::try_from(u64::from(value))
111    }
112}
113impl core::fmt::Display for HydrogenIsotope {
114    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115        match self {
116            Self::H1 => write!(f, "H1"),
117            Self::D => write!(f, "D"),
118            Self::T => write!(f, "T"),
119            Self::H4 => write!(f, "H4"),
120            Self::H5 => write!(f, "H5"),
121            Self::H6 => write!(f, "H6"),
122            Self::H7 => write!(f, "H7"),
123        }
124    }
125}
126#[cfg(test)]
127mod tests {
128    use strum::IntoEnumIterator;
129
130    use super::*;
131    use crate::isotopes::{
132        ElementVariant, IsotopicComposition, MassNumber, MostAbundantIsotope, RelativeAtomicMass,
133    };
134    #[test]
135    fn test_relative_atomic_mass() {
136        for isotope in HydrogenIsotope::iter() {
137            let mass = isotope.relative_atomic_mass();
138            assert!(mass > 0.0, "Mass should be positive for {isotope:?}");
139        }
140    }
141    #[test]
142    fn test_element() {
143        for isotope in HydrogenIsotope::iter() {
144            let element = isotope.element();
145            assert_eq!(element, crate::Element::H, "Element should be correct for {isotope:?}");
146        }
147    }
148    #[test]
149    fn test_mass_number() {
150        for isotope in HydrogenIsotope::iter() {
151            let mass_number = isotope.mass_number();
152            assert!(
153                mass_number > 0 && mass_number < 300,
154                "Mass number should be reasonable for {isotope:?}"
155            );
156        }
157    }
158    #[test]
159    fn test_isotopic_composition() {
160        for isotope in HydrogenIsotope::iter() {
161            let comp = isotope.isotopic_composition();
162            if let Some(c) = comp {
163                assert!(
164                    (0.0..=1.0).contains(&c),
165                    "Composition should be between 0 and 1 for {isotope:?}"
166                );
167            }
168        }
169    }
170    #[test]
171    fn test_most_abundant() {
172        let most_abundant = HydrogenIsotope::most_abundant_isotope();
173        let _ = most_abundant.relative_atomic_mass();
174    }
175    #[test]
176    fn test_from_isotope() {
177        for isotope in HydrogenIsotope::iter() {
178            let iso: crate::Isotope = isotope.into();
179            match iso {
180                crate::Isotope::H(i) => assert_eq!(i, isotope),
181                _ => panic!("Wrong isotope type"),
182            }
183        }
184    }
185    #[test]
186    fn test_from_element() {
187        for isotope in HydrogenIsotope::iter() {
188            let elem: crate::Element = isotope.into();
189            assert_eq!(elem, crate::Element::H);
190        }
191    }
192    #[test]
193    fn test_try_from_mass_number() {
194        for isotope in HydrogenIsotope::iter() {
195            let mass = isotope.mass_number();
196            let iso = HydrogenIsotope::try_from(mass).unwrap();
197            assert_eq!(iso, isotope);
198            let iso_u32 = HydrogenIsotope::try_from(u32::from(mass)).unwrap();
199            assert_eq!(iso_u32, isotope);
200            if let Ok(mass_u8) = u8::try_from(mass) {
201                let iso_u8 = HydrogenIsotope::try_from(mass_u8).unwrap();
202                assert_eq!(iso_u8, isotope);
203            }
204        }
205        assert!(HydrogenIsotope::try_from(0_u16).is_err());
206        assert!(HydrogenIsotope::try_from(1000_u16).is_err());
207        assert!(HydrogenIsotope::try_from(0_u32).is_err());
208        assert!(HydrogenIsotope::try_from(1000_u32).is_err());
209        assert!(HydrogenIsotope::try_from(0_u8).is_err());
210    }
211    #[test]
212    fn test_display() {
213        for isotope in HydrogenIsotope::iter() {
214            let s = alloc::format!("{isotope}");
215            assert!(!s.is_empty(), "Display should not be empty for {isotope:?}");
216        }
217    }
218}