use crate::{
Element,
isotopes::{
ActiniumIsotope, AluminiumIsotope, AmericiumIsotope, AntimonyIsotope, ArgonIsotope,
ArsenicIsotope, AstatineIsotope, BariumIsotope, BerkeliumIsotope, BerylliumIsotope,
BismuthIsotope, BohriumIsotope, BoronIsotope, BromineIsotope, CadmiumIsotope,
CaesiumIsotope, CalciumIsotope, CaliforniumIsotope, CarbonIsotope, CeriumIsotope,
ChlorineIsotope, ChromiumIsotope, CobaltIsotope, CoperniciumIsotope, CopperIsotope,
CuriumIsotope, DarmstadtiumIsotope, DubniumIsotope, DysprosiumIsotope, EinsteiniumIsotope,
ErbiumIsotope, EuropiumIsotope, FermiumIsotope, FleroviumIsotope, FluorineIsotope,
FranciumIsotope, GadoliniumIsotope, GalliumIsotope, GermaniumIsotope, GoldIsotope,
HafniumIsotope, HassiumIsotope, HeliumIsotope, HolmiumIsotope, HydrogenIsotope,
IndiumIsotope, IodineIsotope, IridiumIsotope, IronIsotope, KryptonIsotope,
LanthanumIsotope, LawrenciumIsotope, LeadIsotope, LithiumIsotope, LivermoriumIsotope,
LutetiumIsotope, MagnesiumIsotope, ManganeseIsotope, MeitneriumIsotope, MendeleviumIsotope,
MercuryIsotope, MolybdenumIsotope, MoscoviumIsotope, NeodymiumIsotope, NeonIsotope,
NeptuniumIsotope, NickelIsotope, NihoniumIsotope, NiobiumIsotope, NitrogenIsotope,
NobeliumIsotope, OganessonIsotope, OsmiumIsotope, OxygenIsotope, PalladiumIsotope,
PhosphorusIsotope, PlatinumIsotope, PlutoniumIsotope, PoloniumIsotope, PotassiumIsotope,
PraseodymiumIsotope, PromethiumIsotope, ProtactiniumIsotope, RadiumIsotope, RadonIsotope,
RheniumIsotope, RhodiumIsotope, RoentgeniumIsotope, RubidiumIsotope, RutheniumIsotope,
RutherfordiumIsotope, SamariumIsotope, ScandiumIsotope, SeaborgiumIsotope, SeleniumIsotope,
SiliconIsotope, SilverIsotope, SodiumIsotope, StrontiumIsotope, SulfurIsotope,
TantalumIsotope, TechnetiumIsotope, TelluriumIsotope, TennessineIsotope, TerbiumIsotope,
ThalliumIsotope, ThoriumIsotope, ThuliumIsotope, TinIsotope, TitaniumIsotope,
TungstenIsotope, UraniumIsotope, VanadiumIsotope, XenonIsotope, YtterbiumIsotope,
YttriumIsotope, ZincIsotope, ZirconiumIsotope,
},
};
impl TryFrom<(Element, u64)> for crate::Isotope {
type Error = crate::errors::Error;
#[allow(clippy::too_many_lines)]
fn try_from((element, mass): (Element, u64)) -> Result<Self, Self::Error> {
Ok(match element {
Element::H => Self::H(HydrogenIsotope::try_from(mass)?),
Element::He => Self::He(HeliumIsotope::try_from(mass)?),
Element::Li => Self::Li(LithiumIsotope::try_from(mass)?),
Element::Be => Self::Be(BerylliumIsotope::try_from(mass)?),
Element::B => Self::B(BoronIsotope::try_from(mass)?),
Element::C => Self::C(CarbonIsotope::try_from(mass)?),
Element::N => Self::N(NitrogenIsotope::try_from(mass)?),
Element::O => Self::O(OxygenIsotope::try_from(mass)?),
Element::F => Self::F(FluorineIsotope::try_from(mass)?),
Element::Ne => Self::Ne(NeonIsotope::try_from(mass)?),
Element::Na => Self::Na(SodiumIsotope::try_from(mass)?),
Element::Mg => Self::Mg(MagnesiumIsotope::try_from(mass)?),
Element::Al => Self::Al(AluminiumIsotope::try_from(mass)?),
Element::Si => Self::Si(SiliconIsotope::try_from(mass)?),
Element::P => Self::P(PhosphorusIsotope::try_from(mass)?),
Element::S => Self::S(SulfurIsotope::try_from(mass)?),
Element::Cl => Self::Cl(ChlorineIsotope::try_from(mass)?),
Element::Ar => Self::Ar(ArgonIsotope::try_from(mass)?),
Element::K => Self::K(PotassiumIsotope::try_from(mass)?),
Element::Ca => Self::Ca(CalciumIsotope::try_from(mass)?),
Element::Sc => Self::Sc(ScandiumIsotope::try_from(mass)?),
Element::Ti => Self::Ti(TitaniumIsotope::try_from(mass)?),
Element::V => Self::V(VanadiumIsotope::try_from(mass)?),
Element::Cr => Self::Cr(ChromiumIsotope::try_from(mass)?),
Element::Mn => Self::Mn(ManganeseIsotope::try_from(mass)?),
Element::Fe => Self::Fe(IronIsotope::try_from(mass)?),
Element::Co => Self::Co(CobaltIsotope::try_from(mass)?),
Element::Ni => Self::Ni(NickelIsotope::try_from(mass)?),
Element::Cu => Self::Cu(CopperIsotope::try_from(mass)?),
Element::Zn => Self::Zn(ZincIsotope::try_from(mass)?),
Element::Ga => Self::Ga(GalliumIsotope::try_from(mass)?),
Element::Ge => Self::Ge(GermaniumIsotope::try_from(mass)?),
Element::As => Self::As(ArsenicIsotope::try_from(mass)?),
Element::Se => Self::Se(SeleniumIsotope::try_from(mass)?),
Element::Br => Self::Br(BromineIsotope::try_from(mass)?),
Element::Kr => Self::Kr(KryptonIsotope::try_from(mass)?),
Element::Rb => Self::Rb(RubidiumIsotope::try_from(mass)?),
Element::Sr => Self::Sr(StrontiumIsotope::try_from(mass)?),
Element::Y => Self::Y(YttriumIsotope::try_from(mass)?),
Element::Zr => Self::Zr(ZirconiumIsotope::try_from(mass)?),
Element::Nb => Self::Nb(NiobiumIsotope::try_from(mass)?),
Element::Mo => Self::Mo(MolybdenumIsotope::try_from(mass)?),
Element::Tc => Self::Tc(TechnetiumIsotope::try_from(mass)?),
Element::Ru => Self::Ru(RutheniumIsotope::try_from(mass)?),
Element::Rh => Self::Rh(RhodiumIsotope::try_from(mass)?),
Element::Pd => Self::Pd(PalladiumIsotope::try_from(mass)?),
Element::Ag => Self::Ag(SilverIsotope::try_from(mass)?),
Element::Cd => Self::Cd(CadmiumIsotope::try_from(mass)?),
Element::In => Self::In(IndiumIsotope::try_from(mass)?),
Element::Sn => Self::Sn(TinIsotope::try_from(mass)?),
Element::Sb => Self::Sb(AntimonyIsotope::try_from(mass)?),
Element::Te => Self::Te(TelluriumIsotope::try_from(mass)?),
Element::I => Self::I(IodineIsotope::try_from(mass)?),
Element::Xe => Self::Xe(XenonIsotope::try_from(mass)?),
Element::Cs => Self::Cs(CaesiumIsotope::try_from(mass)?),
Element::Ba => Self::Ba(BariumIsotope::try_from(mass)?),
Element::La => Self::La(LanthanumIsotope::try_from(mass)?),
Element::Ce => Self::Ce(CeriumIsotope::try_from(mass)?),
Element::Pr => Self::Pr(PraseodymiumIsotope::try_from(mass)?),
Element::Nd => Self::Nd(NeodymiumIsotope::try_from(mass)?),
Element::Pm => Self::Pm(PromethiumIsotope::try_from(mass)?),
Element::Sm => Self::Sm(SamariumIsotope::try_from(mass)?),
Element::Eu => Self::Eu(EuropiumIsotope::try_from(mass)?),
Element::Gd => Self::Gd(GadoliniumIsotope::try_from(mass)?),
Element::Tb => Self::Tb(TerbiumIsotope::try_from(mass)?),
Element::Dy => Self::Dy(DysprosiumIsotope::try_from(mass)?),
Element::Ho => Self::Ho(HolmiumIsotope::try_from(mass)?),
Element::Er => Self::Er(ErbiumIsotope::try_from(mass)?),
Element::Tm => Self::Tm(ThuliumIsotope::try_from(mass)?),
Element::Yb => Self::Yb(YtterbiumIsotope::try_from(mass)?),
Element::Lu => Self::Lu(LutetiumIsotope::try_from(mass)?),
Element::Hf => Self::Hf(HafniumIsotope::try_from(mass)?),
Element::Ta => Self::Ta(TantalumIsotope::try_from(mass)?),
Element::W => Self::W(TungstenIsotope::try_from(mass)?),
Element::Re => Self::Re(RheniumIsotope::try_from(mass)?),
Element::Os => Self::Os(OsmiumIsotope::try_from(mass)?),
Element::Ir => Self::Ir(IridiumIsotope::try_from(mass)?),
Element::Pt => Self::Pt(PlatinumIsotope::try_from(mass)?),
Element::Au => Self::Au(GoldIsotope::try_from(mass)?),
Element::Hg => Self::Hg(MercuryIsotope::try_from(mass)?),
Element::Tl => Self::Tl(ThalliumIsotope::try_from(mass)?),
Element::Pb => Self::Pb(LeadIsotope::try_from(mass)?),
Element::Bi => Self::Bi(BismuthIsotope::try_from(mass)?),
Element::Po => Self::Po(PoloniumIsotope::try_from(mass)?),
Element::At => Self::At(AstatineIsotope::try_from(mass)?),
Element::Rn => Self::Rn(RadonIsotope::try_from(mass)?),
Element::Fr => Self::Fr(FranciumIsotope::try_from(mass)?),
Element::Ra => Self::Ra(RadiumIsotope::try_from(mass)?),
Element::Ac => Self::Ac(ActiniumIsotope::try_from(mass)?),
Element::Th => Self::Th(ThoriumIsotope::try_from(mass)?),
Element::Pa => Self::Pa(ProtactiniumIsotope::try_from(mass)?),
Element::U => Self::U(UraniumIsotope::try_from(mass)?),
Element::Np => Self::Np(NeptuniumIsotope::try_from(mass)?),
Element::Pu => Self::Pu(PlutoniumIsotope::try_from(mass)?),
Element::Am => Self::Am(AmericiumIsotope::try_from(mass)?),
Element::Cm => Self::Cm(CuriumIsotope::try_from(mass)?),
Element::Bk => Self::Bk(BerkeliumIsotope::try_from(mass)?),
Element::Cf => Self::Cf(CaliforniumIsotope::try_from(mass)?),
Element::Es => Self::Es(EinsteiniumIsotope::try_from(mass)?),
Element::Fm => Self::Fm(FermiumIsotope::try_from(mass)?),
Element::Md => Self::Md(MendeleviumIsotope::try_from(mass)?),
Element::No => Self::No(NobeliumIsotope::try_from(mass)?),
Element::Lr => Self::Lr(LawrenciumIsotope::try_from(mass)?),
Element::Rf => Self::Rf(RutherfordiumIsotope::try_from(mass)?),
Element::Db => Self::Db(DubniumIsotope::try_from(mass)?),
Element::Sg => Self::Sg(SeaborgiumIsotope::try_from(mass)?),
Element::Bh => Self::Bh(BohriumIsotope::try_from(mass)?),
Element::Hs => Self::Hs(HassiumIsotope::try_from(mass)?),
Element::Mt => Self::Mt(MeitneriumIsotope::try_from(mass)?),
Element::Ds => Self::Ds(DarmstadtiumIsotope::try_from(mass)?),
Element::Rg => Self::Rg(RoentgeniumIsotope::try_from(mass)?),
Element::Cn => Self::Cn(CoperniciumIsotope::try_from(mass)?),
Element::Nh => Self::Nh(NihoniumIsotope::try_from(mass)?),
Element::Fl => Self::Fl(FleroviumIsotope::try_from(mass)?),
Element::Mc => Self::Mc(MoscoviumIsotope::try_from(mass)?),
Element::Lv => Self::Lv(LivermoriumIsotope::try_from(mass)?),
Element::Ts => Self::Ts(TennessineIsotope::try_from(mass)?),
Element::Og => Self::Og(OganessonIsotope::try_from(mass)?),
})
}
}
impl TryFrom<(Element, u32)> for crate::Isotope {
type Error = crate::errors::Error;
#[allow(clippy::too_many_lines)]
fn try_from((element, mass): (Element, u32)) -> Result<Self, Self::Error> {
Self::try_from((element, u64::from(mass)))
}
}
impl TryFrom<(Element, u16)> for crate::Isotope {
type Error = crate::errors::Error;
#[allow(clippy::too_many_lines)]
fn try_from((element, mass): (Element, u16)) -> Result<Self, Self::Error> {
Self::try_from((element, u64::from(mass)))
}
}
impl TryFrom<(Element, u8)> for crate::Isotope {
type Error = crate::errors::Error;
#[allow(clippy::too_many_lines)]
fn try_from((element, mass): (Element, u8)) -> Result<Self, Self::Error> {
Self::try_from((element, u64::from(mass)))
}
}
#[cfg(test)]
mod tests {
use crate::{
Element,
isotopes::{ElementVariant, Isotope, MassNumber},
};
#[test]
fn test_try_from_element_delegation() {
let h1 = Isotope::try_from((Element::H, 1_u8)).unwrap();
assert_eq!(h1, Isotope::H(crate::isotopes::HydrogenIsotope::H1));
let d2 = Isotope::try_from((Element::H, 2_u8)).unwrap();
assert_eq!(d2, Isotope::H(crate::isotopes::HydrogenIsotope::D));
let t3 = Isotope::try_from((Element::H, 3_u8)).unwrap();
assert_eq!(t3, Isotope::H(crate::isotopes::HydrogenIsotope::T));
let c12 = Isotope::try_from((Element::C, 12_u8)).unwrap();
assert_eq!(c12, Isotope::C(crate::isotopes::CarbonIsotope::C12));
let c13 = Isotope::try_from((Element::C, 13_u8)).unwrap();
assert_eq!(c13, Isotope::C(crate::isotopes::CarbonIsotope::C13));
let c14 = Isotope::try_from((Element::C, 14_u8)).unwrap();
assert_eq!(c14, Isotope::C(crate::isotopes::CarbonIsotope::C14));
let o16 = Isotope::try_from((Element::O, 16_u8)).unwrap();
assert_eq!(o16, Isotope::O(crate::isotopes::OxygenIsotope::O16));
let ar36 = Isotope::try_from((Element::Ar, 36_u8)).unwrap();
assert_eq!(ar36, Isotope::Ar(crate::isotopes::ArgonIsotope::Ar36));
let ar40 = Isotope::try_from((Element::Ar, 40_u8)).unwrap();
assert_eq!(ar40, Isotope::Ar(crate::isotopes::ArgonIsotope::Ar40));
}
#[test]
fn test_try_from_element_invalid_mass() {
assert!(Isotope::try_from((Element::H, 0_u8)).is_err());
assert!(Isotope::try_from((Element::H, 8_u8)).is_err()); assert!(Isotope::try_from((Element::C, 7_u8)).is_err()); assert!(Isotope::try_from((Element::C, 24_u8)).is_err()); assert!(Isotope::try_from((Element::O, 10_u8)).is_err()); assert!(Isotope::try_from((Element::O, 29_u8)).is_err()); }
#[test]
fn test_iaea_livechart_missing_isotopes_are_supported() {
let isotopes = [
(Element::Lu, 186_u16),
(Element::Dy, 174),
(Element::Mo, 118),
(Element::Cr, 70),
(Element::Ni, 80),
(Element::Os, 203),
(Element::Pt, 208),
(Element::Se, 63),
(Element::Kr, 67),
(Element::Kr, 68),
(Element::Co, 77),
(Element::Tc, 121),
(Element::Rh, 127),
(Element::Pd, 129),
(Element::Ag, 131),
(Element::Ag, 132),
(Element::Cd, 134),
(Element::In, 136),
(Element::In, 137),
(Element::Sn, 139),
(Element::Sb, 141),
(Element::Sb, 142),
(Element::Te, 144),
(Element::I, 146),
(Element::Ba, 154),
(Element::La, 156),
(Element::Ce, 158),
(Element::Pr, 160),
(Element::Nd, 162),
(Element::Sm, 166),
(Element::Eu, 168),
(Element::Gd, 170),
(Element::Tb, 172),
(Element::Fr, 197),
(Element::Fr, 198),
(Element::Ac, 205),
(Element::Pa, 211),
(Element::U, 215),
(Element::U, 216),
(Element::Am, 223),
(Element::Am, 229),
(Element::Bk, 233),
(Element::Md, 244),
];
for (element, mass_number) in isotopes {
let isotope = Isotope::try_from((element, mass_number)).unwrap();
assert_eq!(isotope.element(), element);
assert_eq!(isotope.mass_number(), mass_number);
assert!(element.isotopes().contains(&isotope));
}
}
#[test]
fn test_nuclear_data_listed_isotopes_are_supported() {
let isotopes = [
(Element::O, 27_u16),
(Element::O, 28),
(Element::Si, 45),
(Element::S, 47),
(Element::Cl, 28),
(Element::Ar, 29),
(Element::Ar, 54),
(Element::K, 57),
(Element::K, 59),
(Element::Ca, 59),
(Element::Ca, 60),
(Element::Na, 39),
(Element::Sc, 37),
(Element::Sc, 62),
(Element::Sc, 63),
(Element::Ti, 65),
(Element::Cu, 84),
(Element::Zn, 86),
(Element::Ga, 88),
(Element::La, 116),
(Element::La, 118),
(Element::La, 119),
(Element::Ce, 119),
(Element::Ce, 120),
(Element::Ce, 159),
(Element::Pr, 122),
(Element::Pr, 123),
(Element::Nd, 124),
(Element::Pm, 126),
(Element::Pm, 127),
(Element::Sm, 128),
(Element::Eu, 133),
(Element::Gd, 133),
(Element::Tb, 136),
(Element::Tb, 137),
(Element::Dy, 138),
(Element::Er, 142),
(Element::Tm, 182),
(Element::Yb, 148),
(Element::Th, 239),
(Element::Pu, 227),
(Element::Am, 231),
(Element::Bk, 235),
(Element::Bk, 252),
(Element::Sg, 268),
(Element::Hs, 272),
(Element::Ds, 275),
(Element::Ds, 276),
(Element::Cn, 280),
(Element::Lv, 289),
];
for (element, mass_number) in isotopes {
let isotope = Isotope::try_from((element, mass_number)).unwrap();
assert_eq!(isotope.element(), element);
assert_eq!(isotope.mass_number(), mass_number);
assert!(element.isotopes().contains(&isotope));
}
}
#[test]
fn test_unobserved_or_inferred_nuclides_are_unsupported() {
let unsupported = [
(Element::Li, 3_u16), (Element::C, 21), (Element::N, 25), (Element::Co, 49), (Element::Cm, 252), (Element::Og, 293), (Element::Og, 295), ];
for (element, mass_number) in unsupported {
assert!(Isotope::try_from((element, mass_number)).is_err());
}
}
#[test]
fn test_try_from_element_strum() {
use strum::IntoEnumIterator;
for element in crate::Element::iter() {
let isotopes = element.isotopes();
for isotope in isotopes {
let mass_number = isotope.mass_number();
let reconstructed = crate::Isotope::try_from((element, mass_number)).unwrap();
assert_eq!(
reconstructed, *isotope,
"Reconstructing isotope {isotope:?} from (element, mass_number) should work",
);
assert_eq!(
reconstructed.element(),
element,
"Reconstructed isotope should belong to element {element:?}",
);
}
}
}
}