use crate::isotopes::ElementVariant;
pub trait AllowedValences {
fn allowed_valences(&self) -> &'static [u8];
}
impl AllowedValences for crate::Element {
#[allow(clippy::match_same_arms)]
#[allow(clippy::too_many_lines)]
fn allowed_valences(&self) -> &'static [u8] {
match self {
Self::H => &[1],
Self::He => &[0],
Self::Li => &[1],
Self::Be => &[2],
Self::B => &[3, 4],
Self::C => &[4],
Self::N => &[3, 5],
Self::O => &[2],
Self::F => &[1],
Self::Ne => &[0],
Self::Na => &[1],
Self::Mg => &[2],
Self::Al => &[3],
Self::Si => &[4, 6],
Self::P => &[3, 5, 6],
Self::S => &[2, 4, 6],
Self::Cl => &[1, 3, 5, 7],
Self::Ar => &[0],
Self::K => &[1],
Self::Ca => &[2],
Self::Sc => &[3],
Self::Ti => &[3, 4],
Self::V => &[2, 3, 4, 5],
Self::Cr => &[2, 3, 6],
Self::Mn => &[2, 3, 4, 6],
Self::Fe => &[2, 3, 4, 6],
Self::Co => &[2, 3],
Self::Ni => &[2, 3],
Self::Cu => &[1, 2],
Self::Zn => &[2],
Self::Ga => &[3],
Self::Ge => &[4],
Self::As => &[3, 5],
Self::Se => &[2, 4, 6],
Self::Br => &[1, 3, 5, 7],
Self::Kr => &[0],
Self::Rb => &[1],
Self::Sr => &[2],
Self::Y => &[3],
Self::Zr => &[4],
Self::Nb => &[3, 5],
Self::Mo => &[3, 4, 5, 6],
Self::Tc => &[7],
Self::Ru => &[2, 3, 4, 6],
Self::Rh => &[2, 3, 4],
Self::Pd => &[2, 4],
Self::Ag => &[1],
Self::Cd => &[2],
Self::In => &[3],
Self::Sn => &[2, 4],
Self::Sb => &[3, 5],
Self::Te => &[2, 4, 6],
Self::I => &[1, 3, 5, 7],
Self::Xe => &[0],
Self::Cs => &[1],
Self::Ba => &[2],
Self::La => &[3],
Self::Ce => &[3, 4],
Self::Pr => &[3, 4],
Self::Nd => &[3],
Self::Pm => &[3],
Self::Sm => &[2, 3],
Self::Eu => &[2, 3],
Self::Gd => &[3],
Self::Tb => &[3, 4],
Self::Dy => &[3],
Self::Ho => &[3],
Self::Er => &[3],
Self::Tm => &[2, 3],
Self::Yb => &[2, 3],
Self::Lu => &[3],
Self::Hf => &[4],
Self::Ta => &[5],
Self::W => &[3, 4, 5, 6],
Self::Re => &[2, 4, 6, 7],
Self::Os => &[2, 3, 4, 6],
Self::Ir => &[2, 3, 4, 6],
Self::Pt => &[2, 4],
Self::Au => &[1, 3],
Self::Hg => &[1, 2],
Self::Tl => &[1, 3],
Self::Pb => &[2, 4],
Self::Bi => &[3, 5],
Self::Po => &[2, 4, 6],
Self::At => &[1, 3, 5, 7],
Self::Rn => &[0],
Self::Fr => &[1],
Self::Ra => &[2],
Self::Ac => &[3],
Self::Th => &[3, 4],
Self::Pa => &[3, 4, 5],
Self::U => &[3, 4, 5, 6],
Self::Np => &[3, 4, 5, 6],
Self::Pu => &[3, 4, 5, 6],
Self::Am => &[3, 4, 5, 6],
Self::Cm => &[3],
Self::Bk => &[3, 4],
Self::Cf => &[3],
Self::Es => &[3],
Self::Fm => &[3],
Self::Md => &[3],
Self::No => &[1],
Self::Lr => &[],
Self::Rf
| Self::Db
| Self::Sg
| Self::Bh
| Self::Hs
| Self::Mt
| Self::Ds
| Self::Rg
| Self::Cn
| Self::Nh
| Self::Fl
| Self::Mc
| Self::Lv
| Self::Ts
| Self::Og => &[],
}
}
}
impl AllowedValences for crate::Isotope {
fn allowed_valences(&self) -> &'static [u8] {
self.element().allowed_valences()
}
}
#[cfg(test)]
mod tests {
use strum::IntoEnumIterator;
use super::AllowedValences;
fn assert_allowed_valence_cases(cases: &[(crate::Element, &'static [u8])]) {
for (element, expected) in cases {
assert_eq!(
element.allowed_valences(),
*expected,
"Allowed valences mismatch for {element:?}",
);
}
}
#[test]
fn test_sorted_ascending() {
for element in crate::Element::iter() {
let valences = element.allowed_valences();
for window in valences.windows(2) {
assert!(
window[0] < window[1],
"Allowed valences should be sorted ascending for {element:?}: {valences:?}",
);
}
}
}
#[test]
fn test_main_group_reference_cases() {
assert_allowed_valence_cases(&[
(crate::Element::C, &[4]),
(crate::Element::N, &[3, 5]),
(crate::Element::S, &[2, 4, 6]),
(crate::Element::Br, &[1, 3, 5, 7]),
(crate::Element::B, &[3, 4]),
(crate::Element::Si, &[4, 6]),
(crate::Element::P, &[3, 5, 6]),
(crate::Element::Ge, &[4]),
(crate::Element::Kr, &[0]),
(crate::Element::Xe, &[0]),
(crate::Element::Rn, &[0]),
]);
}
#[test]
fn test_transition_metals_match_reference_table() {
assert_allowed_valence_cases(&[
(crate::Element::Sc, &[3]),
(crate::Element::Ti, &[3, 4]),
(crate::Element::V, &[2, 3, 4, 5]),
(crate::Element::Cr, &[2, 3, 6]),
(crate::Element::Mn, &[2, 3, 4, 6]),
(crate::Element::Fe, &[2, 3, 4, 6]),
(crate::Element::Co, &[2, 3]),
(crate::Element::Ni, &[2, 3]),
(crate::Element::Cu, &[1, 2]),
(crate::Element::Zn, &[2]),
(crate::Element::Y, &[3]),
(crate::Element::Zr, &[4]),
(crate::Element::Nb, &[3, 5]),
(crate::Element::Mo, &[3, 4, 5, 6]),
(crate::Element::Tc, &[7]),
(crate::Element::Ru, &[2, 3, 4, 6]),
(crate::Element::Rh, &[2, 3, 4]),
(crate::Element::Pd, &[2, 4]),
(crate::Element::Ag, &[1]),
(crate::Element::Cd, &[2]),
(crate::Element::Hf, &[4]),
(crate::Element::Ta, &[5]),
(crate::Element::W, &[3, 4, 5, 6]),
(crate::Element::Re, &[2, 4, 6, 7]),
(crate::Element::Os, &[2, 3, 4, 6]),
(crate::Element::Ir, &[2, 3, 4, 6]),
(crate::Element::Pt, &[2, 4]),
(crate::Element::Au, &[1, 3]),
(crate::Element::Hg, &[1, 2]),
]);
}
#[test]
fn test_lanthanides_match_reference_table() {
assert_allowed_valence_cases(&[
(crate::Element::La, &[3]),
(crate::Element::Ce, &[3, 4]),
(crate::Element::Pr, &[3, 4]),
(crate::Element::Nd, &[3]),
(crate::Element::Pm, &[3]),
(crate::Element::Sm, &[2, 3]),
(crate::Element::Eu, &[2, 3]),
(crate::Element::Gd, &[3]),
(crate::Element::Tb, &[3, 4]),
(crate::Element::Dy, &[3]),
(crate::Element::Ho, &[3]),
(crate::Element::Er, &[3]),
(crate::Element::Tm, &[2, 3]),
(crate::Element::Yb, &[2, 3]),
(crate::Element::Lu, &[3]),
]);
}
#[test]
fn test_actinides_match_reference_table() {
assert_allowed_valence_cases(&[
(crate::Element::Ac, &[3]),
(crate::Element::Th, &[3, 4]),
(crate::Element::Pa, &[3, 4, 5]),
(crate::Element::U, &[3, 4, 5, 6]),
(crate::Element::Np, &[3, 4, 5, 6]),
(crate::Element::Pu, &[3, 4, 5, 6]),
(crate::Element::Am, &[3, 4, 5, 6]),
(crate::Element::Cm, &[3]),
(crate::Element::Bk, &[3, 4]),
(crate::Element::Cf, &[3]),
(crate::Element::Es, &[3]),
(crate::Element::Fm, &[3]),
(crate::Element::Md, &[3]),
(crate::Element::No, &[1]),
]);
}
#[test]
fn test_elements_without_fixed_valence_model() {
assert_allowed_valence_cases(&[
(crate::Element::Lr, &[]),
(crate::Element::Rf, &[]),
(crate::Element::Og, &[]),
]);
}
#[test]
fn test_isotope_delegation() {
for element in crate::Element::iter() {
let element_valences = element.allowed_valences();
for isotope in element.isotopes() {
let isotope_valences = isotope.allowed_valences();
assert_eq!(
element_valences, isotope_valences,
"Allowed valences mismatch for isotope {isotope:?} of element {element:?}",
);
}
}
}
}