periodic_table_on_an_enum/
lib.rs

1//! This is a complete periodic table for rust, including the following fields:
2//! * Atomic number
3//! * Symbol
4//! * Name
5//! * Atomic mass
6//! * CPK Color
7//! * Electron configuration
8//! * Electronegativity
9//! * Atomic radius
10//! * Ionization energy
11//! * Electron affinity
12//! * Oxidation states
13//! * Standard state
14//! * Melting point
15//! * Boiling point
16//! * Density
17//! * Group block
18//! * Year discovered
19
20use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator};
21use std::mem;
22
23include!(concat!(env!("OUT_DIR"), "/data.rs"));
24
25#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
26pub enum GroupBlock {
27    AlkaliMetal,
28    AlkalineEarthMetal,
29    Lanthanide,
30    Actinide,
31    TransitionMetal,
32    PostTransitionMetal,
33    Metalloid,
34    NonMetal,
35    Halogen,
36    NobleGas,
37}
38
39macro_rules! lookup {
40    ($table:expr, $term:expr) => {{
41        // Binary search the term
42        let mut l = 0;
43        let mut r = 117;
44        while l <= r {
45            let m = l + (r - l) / 2;
46            if $table[m].0 == $term {
47                return Some(unsafe { Element::from_id($table[m].1) });
48            }
49            if $table[m].0 < $term {
50                l = m + 1;
51            }
52            if $table[m].0 > $term {
53                r = m - 1;
54            }
55        }
56        None
57    }};
58}
59
60impl Element {
61    pub fn get_oxidation_states(&self) -> &'static [i8] {
62        &OXIDATION_STATES_DATA[OXIDATION_STATES[*self as usize].0 as usize
63            ..OXIDATION_STATES[*self as usize].0 as usize
64                + OXIDATION_STATES[*self as usize].1 as usize][..]
65    }
66
67    /// The id is the atomic number starting at zero
68    #[inline(always)]
69    pub unsafe fn from_id(id: u8) -> Element {
70        mem::transmute(id)
71    }
72
73    pub fn from_symbol(sym: &str) -> Option<Element> {
74        lookup!(SYMBOLS_SORTED_ALPHABETICALLY, sym)
75    }
76
77    /// Name must be lowercase
78    pub fn from_name(name: &str) -> Option<Element> {
79        lookup!(LOWERCASE_NAMES_SORTED_ALPHABETICALLY, name)
80    }
81
82    pub fn from_name_case_insensitive(name: &str) -> Option<Element> {
83        Element::from_name(&name.to_lowercase())
84    }
85
86    pub fn from_atomic_number(z: usize) -> Option<Element> {
87        if z > 118 || z == 0 {
88            return None;
89        }
90        Some(unsafe { mem::transmute((z - 1) as u8) })
91    }
92
93    #[inline(always)]
94    pub fn get_atomic_number(&self) -> usize {
95        *self as usize + 1
96    }
97
98    #[inline(always)]
99    pub fn get_atomic_mass(&self) -> f32 {
100        ATOMIC_MASSES[*self as usize]
101    }
102
103    #[inline(always)]
104    pub fn get_atomic_radius(&self) -> u16 {
105        ATOMIC_RADIUS[*self as usize]
106    }
107
108    #[inline(always)]
109    pub fn get_electronegativity(&self) -> f32 {
110        ELECTRONEGATIVITIES[*self as usize]
111    }
112
113    #[inline(always)]
114    pub fn get_electron_affinity(&self) -> f32 {
115        ELECTRON_AFFINITIES[*self as usize]
116    }
117
118    #[inline(always)]
119    #[deprecated]
120    pub fn get_electron_configuration(&self) -> &'static str {
121        ELECTRON_CONFIGURATIONS[*self as usize]
122    }
123
124    #[inline(always)]
125    pub fn get_electronic_configuration(&self) -> ElectronicConfiguration {
126        ELECTRONIC_CONFIGURATION_PARSED[*self as usize]
127    }
128
129    #[inline(always)]
130    pub fn get_electronic_configuration_str(&self) -> &'static str {
131        ELECTRON_CONFIGURATIONS[*self as usize]
132    }
133
134    #[inline(always)]
135    pub fn get_ionization_energy(&self) -> f32 {
136        IONIZATION_ENERGIES[*self as usize]
137    }
138
139    #[inline(always)]
140    pub fn get_density(&self) -> f32 {
141        DENSITIES[*self as usize]
142    }
143
144    #[inline(always)]
145    pub fn get_melting_point(&self) -> f32 {
146        MELTING_POINTS[*self as usize]
147    }
148
149    #[inline(always)]
150    pub fn get_boiling_point(&self) -> f32 {
151        BOILING_POINTS[*self as usize]
152    }
153
154    #[inline(always)]
155    pub fn get_standard_state(&self) -> StateOfMatter {
156        STANDARD_STATES[*self as usize]
157    }
158
159    #[inline(always)]
160    pub fn get_symbol(&self) -> &'static str {
161        SYMBOLS[*self as usize]
162    }
163
164    #[inline(always)]
165    pub fn get_name(&self) -> &'static str {
166        NAMES[*self as usize]
167    }
168
169    #[inline(always)]
170    pub fn get_year_discovered(&self) -> u16 {
171        YEARS_OF_DISCOVERED[*self as usize]
172    }
173
174    #[inline(always)]
175    pub fn get_group(&self) -> GroupBlock {
176        GROUPS[*self as usize]
177    }
178
179    #[inline(always)]
180    pub fn get_cpk(&self) -> [u8; 3] {
181        CPK[*self as usize]
182    }
183
184    /// The id is the atomic number starting at zero
185    #[inline(always)]
186    pub fn get_id(&self) -> u8 {
187        *self as u8
188    }
189}
190
191pub struct PeriodicTableIterator {
192    r: i8,
193    l: i8,
194}
195
196pub fn periodic_table() -> PeriodicTableIterator {
197    PeriodicTableIterator { l: -1, r: 118 }
198}
199
200impl Iterator for PeriodicTableIterator {
201    type Item = Element;
202
203    fn next(&mut self) -> Option<Self::Item> {
204        self.l += 1;
205        if self.l >= self.r {
206            return None;
207        }
208        let e = unsafe { Element::from_id(self.l as u8) };
209        Some(e)
210    }
211}
212
213impl DoubleEndedIterator for PeriodicTableIterator {
214    fn next_back(&mut self) -> Option<Self::Item> {
215        self.r -= 1;
216        if self.r <= self.l {
217            return None;
218        }
219        let e = unsafe { Element::from_id(self.r as u8) };
220        Some(e)
221    }
222}
223
224impl FusedIterator for PeriodicTableIterator {}
225
226impl ExactSizeIterator for PeriodicTableIterator {
227    fn len(&self) -> usize {
228        (self.r - self.l) as usize
229    }
230}
231
232#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
233pub enum StateOfMatter {
234    Solid,
235    Liquid,
236    Gas,
237}
238
239#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
240pub struct ElectronicConfiguration {
241    pub s: [u8; 7],
242    pub p: [u8; 6],
243    pub d: [u8; 4],
244    pub f: [u8; 2],
245}