elements_rs/isotopes/
hydrogen.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, strum :: EnumIter)]
3#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4pub enum HydrogenIsotope {
6 H1,
8 D,
10 T,
12 H4,
14 H5,
16 H6,
18 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}