#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Element(u8);
impl Element {
pub const H: Element = Element(1);
pub const HE: Element = Element(2);
pub const LI: Element = Element(3);
pub const BE: Element = Element(4);
pub const B: Element = Element(5);
pub const C: Element = Element(6);
pub const N: Element = Element(7);
pub const O: Element = Element(8);
pub const F: Element = Element(9);
pub const NE: Element = Element(10);
pub const NA: Element = Element(11);
pub const MG: Element = Element(12);
pub const AL: Element = Element(13);
pub const SI: Element = Element(14);
pub const P: Element = Element(15);
pub const S: Element = Element(16);
pub const CL: Element = Element(17);
pub const AR: Element = Element(18);
pub const K: Element = Element(19);
pub const CA: Element = Element(20);
pub const SC: Element = Element(21);
pub const TI: Element = Element(22);
pub const V: Element = Element(23);
pub const CR: Element = Element(24);
pub const MN: Element = Element(25);
pub const FE: Element = Element(26);
pub const CO: Element = Element(27);
pub const NI: Element = Element(28);
pub const CU: Element = Element(29);
pub const ZN: Element = Element(30);
pub const GA: Element = Element(31);
pub const GE: Element = Element(32);
pub const AS: Element = Element(33);
pub const SE: Element = Element(34);
pub const BR: Element = Element(35);
pub const KR: Element = Element(36);
pub const RB: Element = Element(37);
pub const SR: Element = Element(38);
pub const Y: Element = Element(39);
pub const ZR: Element = Element(40);
pub const NB: Element = Element(41);
pub const MO: Element = Element(42);
pub const TC: Element = Element(43);
pub const RU: Element = Element(44);
pub const RH: Element = Element(45);
pub const PD: Element = Element(46);
pub const AG: Element = Element(47);
pub const CD: Element = Element(48);
pub const IN: Element = Element(49);
pub const SN: Element = Element(50);
pub const SB: Element = Element(51);
pub const TE: Element = Element(52);
pub const I: Element = Element(53);
pub const XE: Element = Element(54);
pub const CS: Element = Element(55);
pub const BA: Element = Element(56);
pub const LA: Element = Element(57);
pub const CE: Element = Element(58);
pub const PR: Element = Element(59);
pub const ND: Element = Element(60);
pub const PM: Element = Element(61);
pub const SM: Element = Element(62);
pub const EU: Element = Element(63);
pub const GD: Element = Element(64);
pub const TB: Element = Element(65);
pub const DY: Element = Element(66);
pub const HO: Element = Element(67);
pub const ER: Element = Element(68);
pub const TM: Element = Element(69);
pub const YB: Element = Element(70);
pub const LU: Element = Element(71);
pub const HF: Element = Element(72);
pub const TA: Element = Element(73);
pub const W: Element = Element(74);
pub const RE: Element = Element(75);
pub const OS: Element = Element(76);
pub const IR: Element = Element(77);
pub const PT: Element = Element(78);
pub const AU: Element = Element(79);
pub const HG: Element = Element(80);
pub const TL: Element = Element(81);
pub const PB: Element = Element(82);
pub const BI: Element = Element(83);
pub const PO: Element = Element(84);
pub const AT: Element = Element(85);
pub const RN: Element = Element(86);
pub const FR: Element = Element(87);
pub const RA: Element = Element(88);
pub const AC: Element = Element(89);
pub const TH: Element = Element(90);
pub const PA: Element = Element(91);
pub const U: Element = Element(92);
pub const NP: Element = Element(93);
pub const PU: Element = Element(94);
pub const AM: Element = Element(95);
pub const CM: Element = Element(96);
pub const BK: Element = Element(97);
pub const CF: Element = Element(98);
pub const ES: Element = Element(99);
pub const FM: Element = Element(100);
pub const MD: Element = Element(101);
pub const NO: Element = Element(102);
pub const LR: Element = Element(103);
pub const RF: Element = Element(104);
pub const DB: Element = Element(105);
pub const SG: Element = Element(106);
pub const BH: Element = Element(107);
pub const HS: Element = Element(108);
pub const MT: Element = Element(109);
pub const DS: Element = Element(110);
pub const RG: Element = Element(111);
pub const CN: Element = Element(112);
pub const NH: Element = Element(113);
pub const FL: Element = Element(114);
pub const MC: Element = Element(115);
pub const LV: Element = Element(116);
pub const TS: Element = Element(117);
pub const OG: Element = Element(118);
#[inline]
pub const fn from_atomic_number(n: u8) -> Option<Self> {
if n >= 1 && n <= 118 {
Some(Self(n))
} else {
None
}
}
pub fn from_symbol(s: &str) -> Option<Self> {
match s {
"H" => Some(Self::H),
"He" => Some(Self::HE),
"Li" => Some(Self::LI),
"Be" => Some(Self::BE),
"B" => Some(Self::B),
"C" => Some(Self::C),
"N" => Some(Self::N),
"O" => Some(Self::O),
"F" => Some(Self::F),
"Ne" => Some(Self::NE),
"Na" => Some(Self::NA),
"Mg" => Some(Self::MG),
"Al" => Some(Self::AL),
"Si" => Some(Self::SI),
"P" => Some(Self::P),
"S" => Some(Self::S),
"Cl" => Some(Self::CL),
"Ar" => Some(Self::AR),
"K" => Some(Self::K),
"Ca" => Some(Self::CA),
"Sc" => Some(Self::SC),
"Ti" => Some(Self::TI),
"V" => Some(Self::V),
"Cr" => Some(Self::CR),
"Mn" => Some(Self::MN),
"Fe" => Some(Self::FE),
"Co" => Some(Self::CO),
"Ni" => Some(Self::NI),
"Cu" => Some(Self::CU),
"Zn" => Some(Self::ZN),
"Ga" => Some(Self::GA),
"Ge" => Some(Self::GE),
"As" => Some(Self::AS),
"Se" => Some(Self::SE),
"Br" => Some(Self::BR),
"Kr" => Some(Self::KR),
"Rb" => Some(Self::RB),
"Sr" => Some(Self::SR),
"Y" => Some(Self::Y),
"Zr" => Some(Self::ZR),
"Nb" => Some(Self::NB),
"Mo" => Some(Self::MO),
"Tc" => Some(Self::TC),
"Ru" => Some(Self::RU),
"Rh" => Some(Self::RH),
"Pd" => Some(Self::PD),
"Ag" => Some(Self::AG),
"Cd" => Some(Self::CD),
"In" => Some(Self::IN),
"Sn" => Some(Self::SN),
"Sb" => Some(Self::SB),
"Te" => Some(Self::TE),
"I" => Some(Self::I),
"Xe" => Some(Self::XE),
"Cs" => Some(Self::CS),
"Ba" => Some(Self::BA),
"La" => Some(Self::LA),
"Ce" => Some(Self::CE),
"Pr" => Some(Self::PR),
"Nd" => Some(Self::ND),
"Pm" => Some(Self::PM),
"Sm" => Some(Self::SM),
"Eu" => Some(Self::EU),
"Gd" => Some(Self::GD),
"Tb" => Some(Self::TB),
"Dy" => Some(Self::DY),
"Ho" => Some(Self::HO),
"Er" => Some(Self::ER),
"Tm" => Some(Self::TM),
"Yb" => Some(Self::YB),
"Lu" => Some(Self::LU),
"Hf" => Some(Self::HF),
"Ta" => Some(Self::TA),
"W" => Some(Self::W),
"Re" => Some(Self::RE),
"Os" => Some(Self::OS),
"Ir" => Some(Self::IR),
"Pt" => Some(Self::PT),
"Au" => Some(Self::AU),
"Hg" => Some(Self::HG),
"Tl" => Some(Self::TL),
"Pb" => Some(Self::PB),
"Bi" => Some(Self::BI),
"Po" => Some(Self::PO),
"At" => Some(Self::AT),
"Rn" => Some(Self::RN),
"Fr" => Some(Self::FR),
"Ra" => Some(Self::RA),
"Ac" => Some(Self::AC),
"Th" => Some(Self::TH),
"Pa" => Some(Self::PA),
"U" => Some(Self::U),
"Np" => Some(Self::NP),
"Pu" => Some(Self::PU),
"Am" => Some(Self::AM),
"Cm" => Some(Self::CM),
"Bk" => Some(Self::BK),
"Cf" => Some(Self::CF),
"Es" => Some(Self::ES),
"Fm" => Some(Self::FM),
"Md" => Some(Self::MD),
"No" => Some(Self::NO),
"Lr" => Some(Self::LR),
"Rf" => Some(Self::RF),
"Db" => Some(Self::DB),
"Sg" => Some(Self::SG),
"Bh" => Some(Self::BH),
"Hs" => Some(Self::HS),
"Mt" => Some(Self::MT),
"Ds" => Some(Self::DS),
"Rg" => Some(Self::RG),
"Cn" => Some(Self::CN),
"Nh" => Some(Self::NH),
"Fl" => Some(Self::FL),
"Mc" => Some(Self::MC),
"Lv" => Some(Self::LV),
"Ts" => Some(Self::TS),
"Og" => Some(Self::OG),
_ => None,
}
}
#[inline]
pub fn symbol(self) -> &'static str {
SYMBOLS[(self.0 as usize) - 1]
}
#[inline]
pub fn atomic_number(self) -> u8 {
self.0
}
#[inline]
pub fn is_organic_subset(self) -> bool {
matches!(self.0, 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 35 | 53)
}
pub fn normal_valences(self) -> &'static [u8] {
match self.0 {
1 => &[1], 5 => &[3], 6 => &[4], 7 => &[3, 5], 8 => &[2], 9 => &[1], 14 => &[4], 15 => &[3, 5], 16 => &[2, 4, 6], 17 => &[1, 3, 5, 7], 33 => &[3, 5], 34 => &[2, 4, 6], 35 => &[1, 3, 5, 7], 53 => &[1, 3, 5, 7], _ => &[],
}
}
}
impl core::fmt::Display for Element {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(self.symbol())
}
}
static SYMBOLS: [&str; 118] = [
"H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne",
"Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca",
"Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn",
"Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr",
"Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn",
"Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd",
"Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb",
"Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg",
"Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th",
"Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm",
"Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds",
"Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og",
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_roundtrip_symbol() {
for n in 1u8..=118 {
let elem = Element::from_atomic_number(n).unwrap();
let sym = elem.symbol();
let back = Element::from_symbol(sym).unwrap_or_else(|| panic!("no elem for symbol {sym}"));
assert_eq!(elem, back, "roundtrip failed for atomic number {n}");
}
}
#[test]
fn test_organic_subset() {
for sym in &["B", "C", "N", "O", "P", "S", "F", "Cl", "Br", "I"] {
assert!(Element::from_symbol(sym).unwrap().is_organic_subset(), "{sym} should be in organic subset");
}
assert!(!Element::H.is_organic_subset());
assert!(!Element::FE.is_organic_subset());
}
#[test]
fn test_valences() {
assert_eq!(Element::C.normal_valences(), &[4]);
assert_eq!(Element::N.normal_valences(), &[3, 5]);
assert_eq!(Element::S.normal_valences(), &[2, 4, 6]);
}
}