Skip to main content

use_chemical_formula/
formula_term.rs

1use std::collections::BTreeMap;
2use std::fmt;
3
4use crate::{ElementCount, ElementSymbol, FormulaGroup};
5
6/// A formula term: either an element with a count or a parenthesized group.
7#[derive(Clone, Debug, Eq, PartialEq)]
8pub enum FormulaTerm {
9    /// Element term such as `H2` or `Na`.
10    Element {
11        /// The element symbol.
12        symbol: ElementSymbol,
13        /// The element count.
14        count: ElementCount,
15    },
16    /// Parenthesized group term.
17    Group(FormulaGroup),
18}
19
20impl FormulaTerm {
21    /// Creates an element term.
22    #[must_use]
23    pub const fn element(symbol: ElementSymbol, count: ElementCount) -> Self {
24        Self::Element { symbol, count }
25    }
26
27    /// Creates a group term.
28    #[must_use]
29    pub const fn group(group: FormulaGroup) -> Self {
30        Self::Group(group)
31    }
32
33    pub(crate) fn add_counts(&self, counts: &mut BTreeMap<String, u64>, multiplier: u64) {
34        match self {
35            Self::Element { symbol, count } => {
36                let amount = u64::from(count.get()).saturating_mul(multiplier);
37                let entry = counts.entry(symbol.as_str().to_owned()).or_insert(0);
38                *entry = entry.saturating_add(amount);
39            },
40            Self::Group(group) => group.add_counts(counts, multiplier),
41        }
42    }
43}
44
45impl fmt::Display for FormulaTerm {
46    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
47        match self {
48            Self::Element { symbol, count } => {
49                write!(formatter, "{symbol}")?;
50                if !count.is_one() {
51                    write!(formatter, "{count}")?;
52                }
53                Ok(())
54            },
55            Self::Group(group) => write!(formatter, "{group}"),
56        }
57    }
58}