Skip to main content

use_molar_mass/
atomic_mass_entry.rs

1use std::fmt;
2
3use use_chemical_formula::is_valid_element_symbol;
4
5use crate::MolarMassValidationError;
6
7/// A validated element symbol and atomic mass pair.
8#[derive(Clone, Debug, PartialEq)]
9pub struct AtomicMassEntry {
10    symbol: String,
11    atomic_mass: f64,
12}
13
14impl AtomicMassEntry {
15    /// Creates an atomic mass entry in grams per mole.
16    ///
17    /// # Errors
18    ///
19    /// Returns [`MolarMassValidationError::InvalidElementSymbol`] when `symbol`
20    /// does not match a chemical element symbol shape. Returns an atomic-mass
21    /// validation error when `atomic_mass` is not finite and positive.
22    pub fn new(symbol: &str, atomic_mass: f64) -> Result<Self, MolarMassValidationError> {
23        let symbol = symbol.trim();
24
25        if !is_valid_element_symbol(symbol) {
26            return Err(MolarMassValidationError::InvalidElementSymbol(
27                symbol.to_owned(),
28            ));
29        }
30
31        validate_atomic_mass(symbol, atomic_mass)?;
32
33        Ok(Self {
34            symbol: symbol.to_owned(),
35            atomic_mass,
36        })
37    }
38
39    pub(crate) fn from_validated(symbol: String, atomic_mass: f64) -> Self {
40        Self {
41            symbol,
42            atomic_mass,
43        }
44    }
45
46    /// Returns the element symbol.
47    #[must_use]
48    pub fn symbol(&self) -> &str {
49        &self.symbol
50    }
51
52    /// Returns the atomic mass in grams per mole.
53    #[must_use]
54    pub const fn atomic_mass(&self) -> f64 {
55        self.atomic_mass
56    }
57}
58
59impl TryFrom<(&str, f64)> for AtomicMassEntry {
60    type Error = MolarMassValidationError;
61
62    fn try_from(value: (&str, f64)) -> Result<Self, Self::Error> {
63        Self::new(value.0, value.1)
64    }
65}
66
67impl fmt::Display for AtomicMassEntry {
68    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
69        write!(formatter, "{}: {} g/mol", self.symbol, self.atomic_mass)
70    }
71}
72
73pub(crate) fn validate_atomic_mass(
74    symbol: &str,
75    atomic_mass: f64,
76) -> Result<(), MolarMassValidationError> {
77    if !atomic_mass.is_finite() {
78        Err(MolarMassValidationError::NonFiniteAtomicMass {
79            symbol: symbol.to_owned(),
80        })
81    } else if atomic_mass <= 0.0 {
82        Err(MolarMassValidationError::NonPositiveAtomicMass {
83            symbol: symbol.to_owned(),
84        })
85    } else {
86        Ok(())
87    }
88}