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::{all_elements, Element};
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!(period_elements(2)
116            .iter()
117            .any(|element| element.symbol == "C"));
118        assert!(period_elements(2)
119            .iter()
120            .any(|element| element.symbol == "O"));
121
122        assert_eq!(group_elements(18).len(), 7);
123        assert!(group_elements(18)
124            .iter()
125            .any(|element| element.symbol == "He"));
126        assert!(group_elements(18)
127            .iter()
128            .any(|element| element.symbol == "Ne"));
129        assert!(group_elements(18)
130            .iter()
131            .any(|element| element.symbol == "Og"));
132
133        assert!(group_elements(0).is_empty());
134        assert!(period_elements(0).is_empty());
135        assert_eq!(all_elements().len(), 118);
136    }
137
138    #[test]
139    fn exposes_period_and_group_for_common_elements() {
140        assert_eq!(period_for_atomic_number(1), Some(1));
141        assert_eq!(period_for_atomic_number(6), Some(2));
142        assert_eq!(period_for_atomic_number(11), Some(3));
143        assert_eq!(period_for_atomic_number(26), Some(4));
144        assert_eq!(period_for_atomic_number(79), Some(6));
145        assert_eq!(period_for_atomic_number(92), Some(7));
146        assert_eq!(period_for_atomic_number(118), Some(7));
147        assert_eq!(period_for_atomic_number(0), None);
148        assert_eq!(period_for_atomic_number(119), None);
149
150        assert_eq!(group_for_atomic_number(1), Some(1));
151        assert_eq!(group_for_atomic_number(6), Some(14));
152        assert_eq!(group_for_atomic_number(11), Some(1));
153        assert_eq!(group_for_atomic_number(26), Some(8));
154        assert_eq!(group_for_atomic_number(79), Some(11));
155        assert_eq!(group_for_atomic_number(92), None);
156        assert_eq!(group_for_atomic_number(118), Some(18));
157    }
158
159    #[test]
160    fn classifies_conservative_families() {
161        assert!(is_valid_atomic_number(118));
162        assert!(!is_valid_atomic_number(0));
163
164        assert!(is_alkali_metal(11));
165        assert!(!is_alkali_metal(1));
166        assert!(is_alkaline_earth_metal(20));
167        assert!(is_halogen(9));
168        assert!(is_noble_gas(10));
169        assert!(is_lanthanide(57));
170        assert!(is_lanthanide(71));
171        assert!(is_actinide(89));
172        assert!(is_actinide(103));
173        assert!(!is_halogen(10));
174    }
175}