Skip to main content

xpict_core/
elements.rs

1//! Periodic table: atomic number ↔ element symbol.
2//!
3//! Index 0 is the wildcard / dummy atom (`*`). Indices 1..=118 are H..=Og.
4
5/// Symbols by atomic number (`0` → `*`, `1` → `H`, … `118` → `Og`).
6pub const SYMBOLS: [&str; 119] = [
7    "*", "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si",
8    "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu",
9    "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc",
10    "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La",
11    "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu",
12    "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At",
13    "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es",
14    "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Nh",
15    "Fl", "Mc", "Lv", "Ts", "Og",
16];
17
18/// Element symbol for atomic number `z`. Unknown `z` → `"X"`.
19pub fn element_symbol(z: u32) -> &'static str {
20    SYMBOLS.get(z as usize).copied().unwrap_or("X")
21}
22
23/// Atomic number for an element symbol (case-insensitive). `"*"` / `"R"` → `0`.
24pub fn atomic_number(symbol: &str) -> Option<u32> {
25    let s = symbol.trim();
26    if s.is_empty() {
27        return None;
28    }
29    if s == "*" || s.eq_ignore_ascii_case("R") {
30        return Some(0);
31    }
32    for (z, sym) in SYMBOLS.iter().enumerate().skip(1) {
33        if sym.eq_ignore_ascii_case(s) {
34            return Some(z as u32);
35        }
36    }
37    None
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn table_covers_0_to_118() {
46        assert_eq!(SYMBOLS.len(), 119);
47        assert_eq!(SYMBOLS[0], "*");
48        assert_eq!(SYMBOLS[1], "H");
49        assert_eq!(SYMBOLS[6], "C");
50        assert_eq!(SYMBOLS[8], "O");
51        assert_eq!(SYMBOLS[92], "U");
52        assert_eq!(SYMBOLS[118], "Og");
53    }
54
55    #[test]
56    fn symbol_roundtrip() {
57        for z in 0u32..=118 {
58            let sym = element_symbol(z);
59            let back = atomic_number(sym).expect(sym);
60            assert_eq!(back, z, "{sym}");
61        }
62        assert_eq!(element_symbol(999), "X");
63        assert_eq!(atomic_number("fe"), Some(26));
64        assert_eq!(atomic_number("R"), Some(0));
65        assert_eq!(atomic_number("nope"), None);
66        assert_eq!(atomic_number(""), None);
67        assert_eq!(atomic_number("   "), None);
68        assert_eq!(atomic_number("*"), Some(0));
69    }
70}