1pub 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
18pub fn element_symbol(z: u32) -> &'static str {
20 SYMBOLS.get(z as usize).copied().unwrap_or("X")
21}
22
23pub 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}