Skip to main content

use_electron_shell/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4//! Simple electron shell distribution helpers.
5
6mod data;
7
8use data::SHELLS;
9use use_element::element_by_atomic_number;
10
11/// Returns the static shell distribution for an atomic number.
12///
13/// # Examples
14///
15/// ```rust
16/// use use_electron_shell::electron_shells;
17///
18/// assert_eq!(electron_shells(1), Some(vec![1]));
19/// assert_eq!(electron_shells(11), Some(vec![2, 8, 1]));
20/// ```
21#[must_use]
22pub fn electron_shells(atomic_number: u8) -> Option<Vec<u8>> {
23    atomic_number
24        .checked_sub(1)
25        .and_then(|index| SHELLS.get(usize::from(index)))
26        .map(|shells| shells.to_vec())
27}
28
29/// Returns the number of occupied shells in the static distribution.
30#[must_use]
31pub fn shell_count(atomic_number: u8) -> Option<usize> {
32    electron_shells(atomic_number).map(|shells| shells.len())
33}
34
35/// Returns the electron count in the outermost occupied shell.
36#[must_use]
37pub fn outer_shell_electrons(atomic_number: u8) -> Option<u8> {
38    electron_shells(atomic_number).and_then(|shells| shells.last().copied())
39}
40
41/// Returns a conservative main-group valence electron count.
42///
43/// Transition metals, lanthanides, and actinides return `None` because their
44/// practical valence behavior is not well represented by a single introductory value.
45#[must_use]
46pub fn valence_electrons_main_group(atomic_number: u8) -> Option<u8> {
47    element_by_atomic_number(atomic_number).and_then(|element| match element.group {
48        Some(group @ 1..=2) => Some(group),
49        Some(group @ 13..=18) => {
50            if element.atomic_number == 2 {
51                Some(2)
52            } else {
53                Some(group - 10)
54            }
55        }
56        _ => None,
57    })
58}
59
60#[cfg(test)]
61mod tests {
62    use super::{
63        electron_shells, outer_shell_electrons, shell_count, valence_electrons_main_group,
64    };
65
66    #[test]
67    fn exposes_expected_shell_distributions() {
68        assert_eq!(electron_shells(1), Some(vec![1]));
69        assert_eq!(electron_shells(2), Some(vec![2]));
70        assert_eq!(electron_shells(6), Some(vec![2, 4]));
71        assert_eq!(electron_shells(10), Some(vec![2, 8]));
72        assert_eq!(electron_shells(11), Some(vec![2, 8, 1]));
73        assert_eq!(electron_shells(20), Some(vec![2, 8, 8, 2]));
74        assert_eq!(electron_shells(0), None);
75        assert_eq!(electron_shells(119), None);
76    }
77
78    #[test]
79    fn exposes_shell_counts_and_outer_shell_counts() {
80        assert_eq!(shell_count(1), Some(1));
81        assert_eq!(shell_count(11), Some(3));
82        assert_eq!(shell_count(20), Some(4));
83        assert_eq!(outer_shell_electrons(1), Some(1));
84        assert_eq!(outer_shell_electrons(8), Some(6));
85        assert_eq!(outer_shell_electrons(10), Some(8));
86        assert_eq!(outer_shell_electrons(11), Some(1));
87        assert_eq!(outer_shell_electrons(0), None);
88    }
89
90    #[test]
91    fn exposes_conservative_main_group_valence() {
92        assert_eq!(valence_electrons_main_group(1), Some(1));
93        assert_eq!(valence_electrons_main_group(2), Some(2));
94        assert_eq!(valence_electrons_main_group(6), Some(4));
95        assert_eq!(valence_electrons_main_group(11), Some(1));
96        assert_eq!(valence_electrons_main_group(17), Some(7));
97        assert_eq!(valence_electrons_main_group(18), Some(8));
98        assert_eq!(valence_electrons_main_group(26), None);
99        assert_eq!(valence_electrons_main_group(57), None);
100        assert_eq!(valence_electrons_main_group(92), None);
101    }
102}