Skip to main content

use_periodic_table/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4//! Periodic-table lookup and conservative classification helpers.
5
6pub use use_element::{Element, all_elements};
7
8use use_element::element_by_atomic_number;
9
10/// Returns all elements in a period.
11///
12/// # Examples
13///
14/// ```rust
15/// use use_periodic_table::period_elements;
16///
17/// assert_eq!(period_elements(2).len(), 8);
18/// assert!(period_elements(2).iter().any(|element| element.symbol == "C"));
19/// ```
20#[must_use]
21pub fn period_elements(period: u8) -> Vec<Element> {
22    all_elements()
23        .iter()
24        .copied()
25        .filter(|element| element.period == period)
26        .collect()
27}
28
29/// Returns all elements in a group.
30///
31/// # Examples
32///
33/// ```rust
34/// use use_periodic_table::group_elements;
35///
36/// let noble_gases = group_elements(18);
37///
38/// assert!(noble_gases.iter().any(|element| element.symbol == "He"));
39/// assert!(noble_gases.iter().any(|element| element.symbol == "Og"));
40/// ```
41#[must_use]
42pub fn group_elements(group: u8) -> Vec<Element> {
43    all_elements()
44        .iter()
45        .copied()
46        .filter(|element| element.group == Some(group))
47        .collect()
48}
49
50/// Returns the period for an atomic number.
51#[must_use]
52pub fn period_for_atomic_number(atomic_number: u8) -> Option<u8> {
53    element_by_atomic_number(atomic_number).map(|element| element.period)
54}
55
56/// Returns the group for an atomic number.
57#[must_use]
58pub fn group_for_atomic_number(atomic_number: u8) -> Option<u8> {
59    element_by_atomic_number(atomic_number).and_then(|element| element.group)
60}
61
62/// Returns `true` when the atomic number is in the supported range.
63#[must_use]
64pub const fn is_valid_atomic_number(atomic_number: u8) -> bool {
65    matches!(atomic_number, 1..=118)
66}
67
68/// Returns `true` for the alkali metals.
69#[must_use]
70pub const fn is_alkali_metal(atomic_number: u8) -> bool {
71    matches!(atomic_number, 3 | 11 | 19 | 37 | 55 | 87)
72}
73
74/// Returns `true` for the alkaline earth metals.
75#[must_use]
76pub const fn is_alkaline_earth_metal(atomic_number: u8) -> bool {
77    matches!(atomic_number, 4 | 12 | 20 | 38 | 56 | 88)
78}
79
80/// Returns `true` for the halogens.
81#[must_use]
82pub const fn is_halogen(atomic_number: u8) -> bool {
83    matches!(atomic_number, 9 | 17 | 35 | 53 | 85 | 117)
84}
85
86/// Returns `true` for the noble gases.
87#[must_use]
88pub const fn is_noble_gas(atomic_number: u8) -> bool {
89    matches!(atomic_number, 2 | 10 | 18 | 36 | 54 | 86 | 118)
90}
91
92/// Returns `true` for the lanthanides.
93#[must_use]
94pub const fn is_lanthanide(atomic_number: u8) -> bool {
95    matches!(atomic_number, 57..=71)
96}
97
98/// Returns `true` for the actinides.
99#[must_use]
100pub const fn is_actinide(atomic_number: u8) -> bool {
101    matches!(atomic_number, 89..=103)
102}
103
104#[cfg(test)]
105mod tests {
106    use super::{
107        all_elements, group_elements, group_for_atomic_number, is_actinide, is_alkali_metal,
108        is_alkaline_earth_metal, is_halogen, is_lanthanide, is_noble_gas, is_valid_atomic_number,
109        period_elements, period_for_atomic_number,
110    };
111
112    #[test]
113    fn exposes_expected_period_and_group_filters() {
114        assert_eq!(period_elements(2).len(), 8);
115        assert!(
116            period_elements(2)
117                .iter()
118                .any(|element| element.symbol == "C")
119        );
120        assert!(
121            period_elements(2)
122                .iter()
123                .any(|element| element.symbol == "O")
124        );
125
126        assert_eq!(group_elements(18).len(), 7);
127        assert!(
128            group_elements(18)
129                .iter()
130                .any(|element| element.symbol == "He")
131        );
132        assert!(
133            group_elements(18)
134                .iter()
135                .any(|element| element.symbol == "Ne")
136        );
137        assert!(
138            group_elements(18)
139                .iter()
140                .any(|element| element.symbol == "Og")
141        );
142
143        assert!(group_elements(0).is_empty());
144        assert!(period_elements(0).is_empty());
145        assert_eq!(all_elements().len(), 118);
146    }
147
148    #[test]
149    fn exposes_period_and_group_for_common_elements() {
150        assert_eq!(period_for_atomic_number(1), Some(1));
151        assert_eq!(period_for_atomic_number(6), Some(2));
152        assert_eq!(period_for_atomic_number(11), Some(3));
153        assert_eq!(period_for_atomic_number(26), Some(4));
154        assert_eq!(period_for_atomic_number(79), Some(6));
155        assert_eq!(period_for_atomic_number(92), Some(7));
156        assert_eq!(period_for_atomic_number(118), Some(7));
157        assert_eq!(period_for_atomic_number(0), None);
158        assert_eq!(period_for_atomic_number(119), None);
159
160        assert_eq!(group_for_atomic_number(1), Some(1));
161        assert_eq!(group_for_atomic_number(6), Some(14));
162        assert_eq!(group_for_atomic_number(11), Some(1));
163        assert_eq!(group_for_atomic_number(26), Some(8));
164        assert_eq!(group_for_atomic_number(79), Some(11));
165        assert_eq!(group_for_atomic_number(92), None);
166        assert_eq!(group_for_atomic_number(118), Some(18));
167    }
168
169    #[test]
170    fn classifies_conservative_families() {
171        assert!(is_valid_atomic_number(118));
172        assert!(!is_valid_atomic_number(0));
173
174        assert!(is_alkali_metal(11));
175        assert!(!is_alkali_metal(1));
176        assert!(is_alkaline_earth_metal(20));
177        assert!(is_halogen(9));
178        assert!(is_noble_gas(10));
179        assert!(is_lanthanide(57));
180        assert!(is_lanthanide(71));
181        assert!(is_actinide(89));
182        assert!(is_actinide(103));
183        assert!(!is_halogen(10));
184    }
185}