Skip to main content

use_chemical_formula/
chemical_formula.rs

1use std::collections::BTreeMap;
2use std::fmt;
3use std::str::FromStr;
4
5use crate::{FormulaParseError, FormulaPart, HydratePart, parse};
6
7/// A chemical formula with a main part and optional hydrate parts.
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct ChemicalFormula {
10    main_part: FormulaPart,
11    hydrate_parts: Vec<HydratePart>,
12}
13
14impl ChemicalFormula {
15    /// Creates a chemical formula from a main part and hydrate parts.
16    #[must_use]
17    pub fn new(main_part: FormulaPart, hydrate_parts: Vec<HydratePart>) -> Self {
18        Self {
19            main_part,
20            hydrate_parts,
21        }
22    }
23
24    /// Parses a chemical formula string.
25    ///
26    /// # Errors
27    ///
28    /// Returns [`FormulaParseError`] when the input is empty or does not match the supported
29    /// lightweight formula grammar.
30    pub fn parse(input: &str) -> Result<Self, FormulaParseError> {
31        parse::parse_formula(input)
32    }
33
34    /// Returns the main formula part.
35    #[must_use]
36    pub const fn main_part(&self) -> &FormulaPart {
37        &self.main_part
38    }
39
40    /// Returns hydrate parts after the main formula part.
41    #[must_use]
42    pub fn hydrate_parts(&self) -> &[HydratePart] {
43        &self.hydrate_parts
44    }
45
46    /// Returns expanded element counts for the full formula.
47    #[must_use]
48    pub fn element_counts(&self) -> BTreeMap<String, u64> {
49        let mut counts = BTreeMap::new();
50        self.main_part.add_counts(&mut counts, 1);
51        for hydrate_part in &self.hydrate_parts {
52            hydrate_part.add_counts(&mut counts);
53        }
54        counts
55    }
56}
57
58impl fmt::Display for ChemicalFormula {
59    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
60        write!(formatter, "{}", self.main_part)?;
61        for hydrate_part in &self.hydrate_parts {
62            write!(formatter, "ยท{hydrate_part}")?;
63        }
64        Ok(())
65    }
66}
67
68impl FromStr for ChemicalFormula {
69    type Err = FormulaParseError;
70
71    fn from_str(input: &str) -> Result<Self, Self::Err> {
72        Self::parse(input)
73    }
74}