Skip to main content

use_chemical_formula/
formula_group.rs

1use std::collections::BTreeMap;
2use std::fmt;
3
4use crate::{FormulaMultiplier, FormulaTerm, FormulaValidationError};
5
6/// Parenthesized formula terms with a multiplier.
7#[derive(Clone, Debug, Eq, PartialEq)]
8pub struct FormulaGroup {
9    terms: Vec<FormulaTerm>,
10    multiplier: FormulaMultiplier,
11}
12
13impl FormulaGroup {
14    /// Creates a formula group.
15    ///
16    /// # Errors
17    ///
18    /// Returns [`FormulaValidationError::EmptyGroup`] when `terms` is empty.
19    pub fn new(
20        terms: Vec<FormulaTerm>,
21        multiplier: FormulaMultiplier,
22    ) -> Result<Self, FormulaValidationError> {
23        if terms.is_empty() {
24            Err(FormulaValidationError::EmptyGroup)
25        } else {
26            Ok(Self { terms, multiplier })
27        }
28    }
29
30    /// Returns the terms inside the group.
31    #[must_use]
32    pub fn terms(&self) -> &[FormulaTerm] {
33        &self.terms
34    }
35
36    /// Returns the group multiplier.
37    #[must_use]
38    pub const fn multiplier(&self) -> FormulaMultiplier {
39        self.multiplier
40    }
41
42    pub(crate) fn add_counts(&self, counts: &mut BTreeMap<String, u64>, multiplier: u64) {
43        let combined_multiplier = multiplier.saturating_mul(u64::from(self.multiplier.get()));
44        for term in &self.terms {
45            term.add_counts(counts, combined_multiplier);
46        }
47    }
48}
49
50impl fmt::Display for FormulaGroup {
51    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
52        formatter.write_str("(")?;
53        for term in &self.terms {
54            write!(formatter, "{term}")?;
55        }
56        formatter.write_str(")")?;
57        if !self.multiplier.is_one() {
58            write!(formatter, "{}", self.multiplier)?;
59        }
60        Ok(())
61    }
62}