1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
7pub struct Element(u8);
8
9impl Element {
10 pub const H: Element = Element(1);
12 pub const HE: Element = Element(2);
13 pub const LI: Element = Element(3);
14 pub const BE: Element = Element(4);
15 pub const B: Element = Element(5);
16 pub const C: Element = Element(6);
17 pub const N: Element = Element(7);
18 pub const O: Element = Element(8);
19 pub const F: Element = Element(9);
20 pub const NE: Element = Element(10);
21 pub const NA: Element = Element(11);
22 pub const MG: Element = Element(12);
23 pub const AL: Element = Element(13);
24 pub const SI: Element = Element(14);
25 pub const P: Element = Element(15);
26 pub const S: Element = Element(16);
27 pub const CL: Element = Element(17);
28 pub const AR: Element = Element(18);
29 pub const K: Element = Element(19);
30 pub const CA: Element = Element(20);
31 pub const SC: Element = Element(21);
32 pub const TI: Element = Element(22);
33 pub const V: Element = Element(23);
34 pub const CR: Element = Element(24);
35 pub const MN: Element = Element(25);
36 pub const FE: Element = Element(26);
37 pub const CO: Element = Element(27);
38 pub const NI: Element = Element(28);
39 pub const CU: Element = Element(29);
40 pub const ZN: Element = Element(30);
41 pub const GA: Element = Element(31);
42 pub const GE: Element = Element(32);
43 pub const AS: Element = Element(33);
44 pub const SE: Element = Element(34);
45 pub const BR: Element = Element(35);
46 pub const KR: Element = Element(36);
47 pub const RB: Element = Element(37);
48 pub const SR: Element = Element(38);
49 pub const Y: Element = Element(39);
50 pub const ZR: Element = Element(40);
51 pub const NB: Element = Element(41);
52 pub const MO: Element = Element(42);
53 pub const TC: Element = Element(43);
54 pub const RU: Element = Element(44);
55 pub const RH: Element = Element(45);
56 pub const PD: Element = Element(46);
57 pub const AG: Element = Element(47);
58 pub const CD: Element = Element(48);
59 pub const IN: Element = Element(49);
60 pub const SN: Element = Element(50);
61 pub const SB: Element = Element(51);
62 pub const TE: Element = Element(52);
63 pub const I: Element = Element(53);
64 pub const XE: Element = Element(54);
65 pub const CS: Element = Element(55);
66 pub const BA: Element = Element(56);
67 pub const LA: Element = Element(57);
68 pub const CE: Element = Element(58);
69 pub const PR: Element = Element(59);
70 pub const ND: Element = Element(60);
71 pub const PM: Element = Element(61);
72 pub const SM: Element = Element(62);
73 pub const EU: Element = Element(63);
74 pub const GD: Element = Element(64);
75 pub const TB: Element = Element(65);
76 pub const DY: Element = Element(66);
77 pub const HO: Element = Element(67);
78 pub const ER: Element = Element(68);
79 pub const TM: Element = Element(69);
80 pub const YB: Element = Element(70);
81 pub const LU: Element = Element(71);
82 pub const HF: Element = Element(72);
83 pub const TA: Element = Element(73);
84 pub const W: Element = Element(74);
85 pub const RE: Element = Element(75);
86 pub const OS: Element = Element(76);
87 pub const IR: Element = Element(77);
88 pub const PT: Element = Element(78);
89 pub const AU: Element = Element(79);
90 pub const HG: Element = Element(80);
91 pub const TL: Element = Element(81);
92 pub const PB: Element = Element(82);
93 pub const BI: Element = Element(83);
94 pub const PO: Element = Element(84);
95 pub const AT: Element = Element(85);
96 pub const RN: Element = Element(86);
97 pub const FR: Element = Element(87);
98 pub const RA: Element = Element(88);
99 pub const AC: Element = Element(89);
100 pub const TH: Element = Element(90);
101 pub const PA: Element = Element(91);
102 pub const U: Element = Element(92);
103 pub const NP: Element = Element(93);
104 pub const PU: Element = Element(94);
105 pub const AM: Element = Element(95);
106 pub const CM: Element = Element(96);
107 pub const BK: Element = Element(97);
108 pub const CF: Element = Element(98);
109 pub const ES: Element = Element(99);
110 pub const FM: Element = Element(100);
111 pub const MD: Element = Element(101);
112 pub const NO: Element = Element(102);
113 pub const LR: Element = Element(103);
114 pub const RF: Element = Element(104);
115 pub const DB: Element = Element(105);
116 pub const SG: Element = Element(106);
117 pub const BH: Element = Element(107);
118 pub const HS: Element = Element(108);
119 pub const MT: Element = Element(109);
120 pub const DS: Element = Element(110);
121 pub const RG: Element = Element(111);
122 pub const CN: Element = Element(112);
123 pub const NH: Element = Element(113);
124 pub const FL: Element = Element(114);
125 pub const MC: Element = Element(115);
126 pub const LV: Element = Element(116);
127 pub const TS: Element = Element(117);
128 pub const OG: Element = Element(118);
129
130 #[inline]
134 pub const fn from_atomic_number(n: u8) -> Option<Self> {
135 if n >= 1 && n <= 118 {
136 Some(Self(n))
137 } else {
138 None
139 }
140 }
141
142 pub fn from_symbol(s: &str) -> Option<Self> {
145 match s {
146 "H" => Some(Self::H),
147 "He" => Some(Self::HE),
148 "Li" => Some(Self::LI),
149 "Be" => Some(Self::BE),
150 "B" => Some(Self::B),
151 "C" => Some(Self::C),
152 "N" => Some(Self::N),
153 "O" => Some(Self::O),
154 "F" => Some(Self::F),
155 "Ne" => Some(Self::NE),
156 "Na" => Some(Self::NA),
157 "Mg" => Some(Self::MG),
158 "Al" => Some(Self::AL),
159 "Si" => Some(Self::SI),
160 "P" => Some(Self::P),
161 "S" => Some(Self::S),
162 "Cl" => Some(Self::CL),
163 "Ar" => Some(Self::AR),
164 "K" => Some(Self::K),
165 "Ca" => Some(Self::CA),
166 "Sc" => Some(Self::SC),
167 "Ti" => Some(Self::TI),
168 "V" => Some(Self::V),
169 "Cr" => Some(Self::CR),
170 "Mn" => Some(Self::MN),
171 "Fe" => Some(Self::FE),
172 "Co" => Some(Self::CO),
173 "Ni" => Some(Self::NI),
174 "Cu" => Some(Self::CU),
175 "Zn" => Some(Self::ZN),
176 "Ga" => Some(Self::GA),
177 "Ge" => Some(Self::GE),
178 "As" => Some(Self::AS),
179 "Se" => Some(Self::SE),
180 "Br" => Some(Self::BR),
181 "Kr" => Some(Self::KR),
182 "Rb" => Some(Self::RB),
183 "Sr" => Some(Self::SR),
184 "Y" => Some(Self::Y),
185 "Zr" => Some(Self::ZR),
186 "Nb" => Some(Self::NB),
187 "Mo" => Some(Self::MO),
188 "Tc" => Some(Self::TC),
189 "Ru" => Some(Self::RU),
190 "Rh" => Some(Self::RH),
191 "Pd" => Some(Self::PD),
192 "Ag" => Some(Self::AG),
193 "Cd" => Some(Self::CD),
194 "In" => Some(Self::IN),
195 "Sn" => Some(Self::SN),
196 "Sb" => Some(Self::SB),
197 "Te" => Some(Self::TE),
198 "I" => Some(Self::I),
199 "Xe" => Some(Self::XE),
200 "Cs" => Some(Self::CS),
201 "Ba" => Some(Self::BA),
202 "La" => Some(Self::LA),
203 "Ce" => Some(Self::CE),
204 "Pr" => Some(Self::PR),
205 "Nd" => Some(Self::ND),
206 "Pm" => Some(Self::PM),
207 "Sm" => Some(Self::SM),
208 "Eu" => Some(Self::EU),
209 "Gd" => Some(Self::GD),
210 "Tb" => Some(Self::TB),
211 "Dy" => Some(Self::DY),
212 "Ho" => Some(Self::HO),
213 "Er" => Some(Self::ER),
214 "Tm" => Some(Self::TM),
215 "Yb" => Some(Self::YB),
216 "Lu" => Some(Self::LU),
217 "Hf" => Some(Self::HF),
218 "Ta" => Some(Self::TA),
219 "W" => Some(Self::W),
220 "Re" => Some(Self::RE),
221 "Os" => Some(Self::OS),
222 "Ir" => Some(Self::IR),
223 "Pt" => Some(Self::PT),
224 "Au" => Some(Self::AU),
225 "Hg" => Some(Self::HG),
226 "Tl" => Some(Self::TL),
227 "Pb" => Some(Self::PB),
228 "Bi" => Some(Self::BI),
229 "Po" => Some(Self::PO),
230 "At" => Some(Self::AT),
231 "Rn" => Some(Self::RN),
232 "Fr" => Some(Self::FR),
233 "Ra" => Some(Self::RA),
234 "Ac" => Some(Self::AC),
235 "Th" => Some(Self::TH),
236 "Pa" => Some(Self::PA),
237 "U" => Some(Self::U),
238 "Np" => Some(Self::NP),
239 "Pu" => Some(Self::PU),
240 "Am" => Some(Self::AM),
241 "Cm" => Some(Self::CM),
242 "Bk" => Some(Self::BK),
243 "Cf" => Some(Self::CF),
244 "Es" => Some(Self::ES),
245 "Fm" => Some(Self::FM),
246 "Md" => Some(Self::MD),
247 "No" => Some(Self::NO),
248 "Lr" => Some(Self::LR),
249 "Rf" => Some(Self::RF),
250 "Db" => Some(Self::DB),
251 "Sg" => Some(Self::SG),
252 "Bh" => Some(Self::BH),
253 "Hs" => Some(Self::HS),
254 "Mt" => Some(Self::MT),
255 "Ds" => Some(Self::DS),
256 "Rg" => Some(Self::RG),
257 "Cn" => Some(Self::CN),
258 "Nh" => Some(Self::NH),
259 "Fl" => Some(Self::FL),
260 "Mc" => Some(Self::MC),
261 "Lv" => Some(Self::LV),
262 "Ts" => Some(Self::TS),
263 "Og" => Some(Self::OG),
264 _ => None,
265 }
266 }
267
268 #[inline]
270 pub fn symbol(self) -> &'static str {
271 SYMBOLS[(self.0 as usize) - 1]
272 }
273
274 #[inline]
276 pub fn atomic_number(self) -> u8 {
277 self.0
278 }
279
280 #[inline]
283 pub fn is_organic_subset(self) -> bool {
284 matches!(self.0, 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 35 | 53)
285 }
286
287 pub fn normal_valences(self) -> &'static [u8] {
290 match self.0 {
291 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], _ => &[],
306 }
307 }
308}
309
310impl core::fmt::Display for Element {
311 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
312 f.write_str(self.symbol())
313 }
314}
315
316static SYMBOLS: [&str; 118] = [
318 "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne",
319 "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca",
320 "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn",
321 "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr",
322 "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn",
323 "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd",
324 "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb",
325 "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg",
326 "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th",
327 "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm",
328 "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds",
329 "Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og",
330];
331
332#[cfg(test)]
333mod tests {
334 use super::*;
335
336 #[test]
337 fn test_roundtrip_symbol() {
338 for n in 1u8..=118 {
339 let elem = Element::from_atomic_number(n).unwrap();
340 let sym = elem.symbol();
341 let back = Element::from_symbol(sym).unwrap_or_else(|| panic!("no elem for symbol {sym}"));
342 assert_eq!(elem, back, "roundtrip failed for atomic number {n}");
343 }
344 }
345
346 #[test]
347 fn test_organic_subset() {
348 for sym in &["B", "C", "N", "O", "P", "S", "F", "Cl", "Br", "I"] {
349 assert!(Element::from_symbol(sym).unwrap().is_organic_subset(), "{sym} should be in organic subset");
350 }
351 assert!(!Element::H.is_organic_subset());
352 assert!(!Element::FE.is_organic_subset());
353 }
354
355 #[test]
356 fn test_valences() {
357 assert_eq!(Element::C.normal_valences(), &[4]);
358 assert_eq!(Element::N.normal_valences(), &[3, 5]);
359 assert_eq!(Element::S.normal_valences(), &[2, 4, 6]);
360 }
361}