1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use use_element::{all_elements, element_by_symbol};
7
8#[must_use]
19pub const fn is_valid_atomic_number(value: u8) -> bool {
20 matches!(value, 1..=118)
21}
22
23#[must_use]
25pub fn atomic_number_from_symbol(symbol: &str) -> Option<u8> {
26 element_by_symbol(symbol).map(|element| element.atomic_number)
27}
28
29#[must_use]
31pub fn atomic_number_from_name(name: &str) -> Option<u8> {
32 let normalized = name.trim();
33
34 if normalized.is_empty() {
35 return None;
36 }
37
38 all_elements()
39 .iter()
40 .find(|element| element.name.eq_ignore_ascii_case(normalized))
41 .map(|element| element.atomic_number)
42}
43
44#[must_use]
46pub fn proton_count(atomic_number: u8) -> Option<u8> {
47 is_valid_atomic_number(atomic_number).then_some(atomic_number)
48}
49
50#[must_use]
52pub fn electron_count_neutral_atom(atomic_number: u8) -> Option<u8> {
53 proton_count(atomic_number)
54}
55
56#[cfg(test)]
57mod tests {
58 use super::{
59 atomic_number_from_name, atomic_number_from_symbol, electron_count_neutral_atom,
60 is_valid_atomic_number, proton_count,
61 };
62
63 #[test]
64 fn validates_range() {
65 assert!(is_valid_atomic_number(1));
66 assert!(is_valid_atomic_number(118));
67 assert!(!is_valid_atomic_number(0));
68 assert!(!is_valid_atomic_number(119));
69 }
70
71 #[test]
72 fn looks_up_symbols_and_names() {
73 assert_eq!(atomic_number_from_symbol("H"), Some(1));
74 assert_eq!(atomic_number_from_symbol("C"), Some(6));
75 assert_eq!(atomic_number_from_symbol("O"), Some(8));
76 assert_eq!(atomic_number_from_symbol("Na"), Some(11));
77 assert_eq!(atomic_number_from_symbol("Fe"), Some(26));
78 assert_eq!(atomic_number_from_symbol("Au"), Some(79));
79 assert_eq!(atomic_number_from_symbol("bad"), None);
80
81 assert_eq!(atomic_number_from_name("Hydrogen"), Some(1));
82 assert_eq!(atomic_number_from_name("carbon"), Some(6));
83 assert_eq!(atomic_number_from_name(" oxygen "), Some(8));
84 assert_eq!(atomic_number_from_name("Sodium"), Some(11));
85 assert_eq!(atomic_number_from_name("Iron"), Some(26));
86 assert_eq!(atomic_number_from_name("Gold"), Some(79));
87 assert_eq!(atomic_number_from_name("Uranium"), Some(92));
88 assert_eq!(atomic_number_from_name("Oganesson"), Some(118));
89 assert_eq!(atomic_number_from_name("invalid"), None);
90 }
91
92 #[test]
93 fn exposes_neutral_atom_counts() {
94 assert_eq!(proton_count(6), Some(6));
95 assert_eq!(electron_count_neutral_atom(6), Some(6));
96 assert_eq!(proton_count(79), Some(79));
97 assert_eq!(electron_count_neutral_atom(79), Some(79));
98 assert_eq!(proton_count(0), None);
99 assert_eq!(electron_count_neutral_atom(119), None);
100 }
101}