chemp 0.9.6

chemical formulas parser
Documentation
use crate::tokens::{Component, Element, Hydrate};

#[derive(Debug, PartialEq)]
pub struct Substance {
    coefficient: usize,
    composition: Vec<Component>,
    hydrate: Option<Hydrate>,
}

impl Substance {
    pub(crate) fn new() -> Self {
        Self {
            coefficient: 1,
            composition: vec![],
            hydrate: None,
        }
    }

    #[allow(unused)]
    pub(crate) fn from(
        coefficient: usize,
        composition: Vec<Component>,
        hydrate: Option<Hydrate>,
    ) -> Self {
        Self {
            coefficient,
            composition,
            hydrate,
        }
    }

    pub(crate) fn add_coefficient(&mut self, coefficient: usize) {
        self.coefficient = coefficient;
    }

    pub(crate) fn add_component(&mut self, component: Component) {
        self.composition.push(component);
    }

    pub(crate) fn add_hydrate(&mut self, hydrate: Hydrate) {
        self.hydrate = Some(hydrate);
    }

    pub(crate) fn elements(&self) -> Vec<Element> {
        let mut elements: Vec<Element> = Vec::new();

        self.composition
            .iter()
            .for_each(|component| match component {
                Component::Element(element) => {
                    elements.push(Element::multiply(element, self.coefficient));
                }

                Component::Group(group) => {
                    group.elements().iter().for_each(|element| {
                        elements.push(Element::multiply(element, self.coefficient));
                    });
                }
            });

        if let Some(hydrate) = &self.hydrate {
            hydrate.elements().iter().for_each(|element| {
                elements.push(Element::multiply(element, self.coefficient));
            });
        }

        elements
    }
}

#[cfg(test)]
mod tests {
    use crate::tokens::{Component, Element, Hydrate, Substance};

    #[test]
    fn coefficient_multiplication() {
        let substance = Substance::from(
            3,
            vec![
                Component::Element(Element::from("Mg", 1)),
                Component::Element(Element::from("S", 1)),
                Component::Element(Element::from("O", 4)),
            ],
            Some(Hydrate::from(
                7,
                vec![Element::from("H", 2), Element::from("O", 1)],
            )),
        );

        assert_eq!(
            substance.elements(),
            vec![
                Element::from("Mg", 3),
                Element::from("S", 3),
                Element::from("O", 12),
                Element::from("H", 42),
                Element::from("O", 21),
            ]
        );
    }
}