chemistru_elements/
lib.rs

1//! # Chemistru Elements
2//!
3//! Provides a static vec of all the elements, with data loaded from a JSON file.
4//!
5//! ## Static Vector
6//!
7//! The elements are stored in the lazily-initialised vector `chemistru_elements::ELEMENTS`
8//!
9//! ### Getting Elements By Atomic (Proton) Number
10//!
11//! ```rust
12//! // Atomic (proton) number, in this case, hydrogen
13//! let z = 1;
14//!
15//! // Static reference to the struct representing hydrogen
16//! let element = chemistru_elements::element_from_atomic_number(z);
17//! ```
18//!
19//! ### Getting Elements By Name
20//!
21//! ```rust
22//! // Name of element
23//! // Case insensitive and accepts multiple spellings
24//! // i.e. 'Cesium', 'Caesium', 'CaEsIuM' will all work
25//! let name_1 = "caesium";
26//! let name_2 = "cesium";
27//!
28//! let element_1 = chemistru_elements::element_from_name(name_1)
29//! let element_2 = chemistru_elements::element_from_name(name_2)
30//!
31//! assert_eq!(element_1, element_2)
32//! ```
33//!
34//! ### Preloading Elements
35//!
36//! Since the static vector of `Element`s is created using `lazy_static`, it will not be initialised until it is used (lazy initialisation)
37//!
38//! This ensures that the static vector of `Element`s is initialised. This is useful if initialising the element vector later would cause some tangible delay for the user.
39//!
40//! #### Without
41//!
42//! ```rust
43//! operation_user_sees();
44//!
45//! // May cause a tangible delay (interacting with io)
46//! let element = ELEMENT[0];
47//!
48//! operation_user_sees();
49//! ```
50//!
51//! #### With
52//!
53//! ```rust
54//! // Pre-initialise the vector of elements
55//! chemistru_elements::preload_elements();
56//!
57//! operation_user_sees();
58//!
59//! // Virually no delay (trivial operation)
60//! let element = ELEMENT[0];
61//!
62//! operation_user_sees();
63//! ```
64
65#![forbid(clippy::pedantic)]
66#![forbid(clippy::unwrap_used)]
67#![forbid(clippy::missing_const_for_fn)]
68#![forbid(unsafe_code)]
69
70#[cfg(feature = "to_tokens")]
71mod tokens;
72
73mod raw;
74
75pub mod atomic;
76pub mod electron;
77pub mod misc;
78pub mod physical;
79pub mod table;
80pub mod utils;
81
82use crate::{
83    atomic::AtomicData, electron::ElectronData, misc::MiscData, physical::PhysicalData,
84    raw::RawElement, table::TableData,
85};
86
87use std::fmt::Display;
88use std::sync::LazyLock;
89
90#[rustfmt::skip]
91pub static ELEMENTS: LazyLock<Vec<Element>> = LazyLock::new(|| {
92    let raw_elements: Vec<RawElement> = serde_json::from_str(include_str!("../db.json")).expect("Failed to load json data");
93    raw_elements.iter().map(|e| e.clone().sanitise()).collect()
94});
95
96/// Basic elemental representation containing a variety of pieces of data about that element.
97#[derive(Clone, Debug, PartialEq, PartialOrd)]
98pub struct Element {
99    pub(crate) name: &'static str,
100    pub(crate) symbol: &'static str,
101    pub(crate) atomic_data: AtomicData,
102    pub(crate) electron_data: ElectronData,
103    pub(crate) physical_data: PhysicalData,
104    pub(crate) table_data: TableData,
105    pub(crate) misc_data: MiscData,
106}
107
108impl Element {
109    #[must_use]
110    pub const fn name(&self) -> &'static str {
111        self.name
112    }
113
114    #[must_use]
115    pub const fn symbol(&self) -> &'static str {
116        self.symbol
117    }
118
119    #[must_use]
120    pub const fn atomic_data(&self) -> &AtomicData {
121        &self.atomic_data
122    }
123
124    #[must_use]
125    pub const fn electron_data(&self) -> &ElectronData {
126        &self.electron_data
127    }
128
129    #[must_use]
130    pub const fn physical_data(&self) -> &PhysicalData {
131        &self.physical_data
132    }
133
134    #[must_use]
135    pub const fn table_data(&self) -> &TableData {
136        &self.table_data
137    }
138
139    #[must_use]
140    pub const fn misc_data(&self) -> &MiscData {
141        &self.misc_data
142    }
143
144    #[must_use]
145    pub const fn new(
146        name: &'static str,
147        symbol: &'static str,
148        atomic_data: AtomicData,
149        electron_data: ElectronData,
150        physical_data: PhysicalData,
151        table_data: TableData,
152        misc_data: MiscData,
153    ) -> Self {
154        Self {
155            name,
156            symbol,
157            atomic_data,
158            electron_data,
159            physical_data,
160            table_data,
161            misc_data,
162        }
163    }
164}
165
166impl Display for Element {
167    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168        f.write_fmt(format_args!(
169            "{}-{}",
170            self.name, self.atomic_data.atomic_number
171        ))
172    }
173}
174
175pub mod prelude {
176    pub use super::ELEMENTS;
177    pub use super::Element;
178    pub use super::utils::element_from_atomic_number;
179    pub use super::utils::element_from_name;
180    pub use super::utils::preload_elements;
181}
182
183#[cfg(test)]
184mod tests {
185    use super::*;
186
187    #[test]
188    fn test_getting_elements_by_atomic_number() {
189        utils::preload_elements();
190
191        let hydrogen = utils::element_from_atomic_number(1);
192        let helium = utils::element_from_atomic_number(2);
193
194        assert_eq!(
195            hydrogen.expect("We know this exists").name().to_lowercase(),
196            "hydrogen"
197        );
198        assert_eq!(
199            helium.expect("We know this exists").name().to_lowercase(),
200            "helium"
201        );
202    }
203
204    #[test]
205    fn test_getting_elements_by_name() {
206        utils::preload_elements();
207
208        let hydrogen = utils::element_from_name("hydrogen");
209        let helium = utils::element_from_name("helium");
210
211        assert_eq!(
212            hydrogen
213                .expect("We know this exists")
214                .atomic_data
215                .atomic_number,
216            1
217        );
218        assert_eq!(
219            helium
220                .expect("We know this exists")
221                .atomic_data
222                .atomic_number,
223            2
224        );
225    }
226}