chemp/lib.rs
1//! chemp is a tool for parsing chemical formulas.
2//!
3//! takes molecular formula of substance. for given correct formula it extracts information about compound:
4//! - chemical composition
5//! - molar mass
6//! - mass percent of each element in composition
7//!
8//! ##### Usage
9//!
10//! ```rust
11//! use chemp;
12//!
13//! let compound = chemp::parse("MgSO4*7H2O").unwrap();
14//!
15//! // getters for each component of compound
16//! compound.components().values().for_each(|component| {
17//! // get mass of all atoms of element in compound
18//! component.mass();
19//!
20//! // get percent of component mass to compound mass
21//! component.mass_percent();
22//!
23//! // get atoms count of element in compound
24//! component.atoms_count();
25//!
26//! // get chemical element symbol
27//! component.chemical_element().symbol();
28//!
29//! // get chemical element atomic weight
30//! component.chemical_element().atomic_weight();
31//! });
32//!
33//! // list of elements in order they parsed
34//! // nested groups are flattened
35//! compound.composition().iter().for_each(|element| {
36//! // get subscript of element
37//! element.subscript();
38//!
39//! // get chemical element symbol
40//! element.chemical_element().symbol();
41//!
42//! // get chemical element atomic weight
43//! element.chemical_element().atomic_weight();
44//! });
45//!
46//! // get molar mass of compound
47//! compound.molar_mass();
48//!
49//! println!("compound: {:#?}", compound);
50//!
51//! // compound: Compound {
52//! // composition: [
53//! // Element {
54//! // chemical_element: Magnesium,
55//! // subscript: 1,
56//! // },
57//! // Element {
58//! // chemical_element: Sulfur,
59//! // subscript: 1,
60//! // },
61//! // Element {
62//! // chemical_element: Oxygen,
63//! // subscript: 4,
64//! // },
65//! // Element {
66//! // chemical_element: Hydrogen,
67//! // subscript: 14,
68//! // },
69//! // Element {
70//! // chemical_element: Oxygen,
71//! // subscript: 7,
72//! // },
73//! // ],
74//! // components: {
75//! // "O": Component {
76//! // chemical_element: Oxygen,
77//! // atoms_count: 11,
78//! // mass_percent: 71.40498,
79//! // },
80//! // "S": Component {
81//! // chemical_element: Sulfur,
82//! // atoms_count: 1,
83//! // mass_percent: 13.007879,
84//! // },
85//! // "Mg": Component {
86//! // chemical_element: Magnesium,
87//! // atoms_count: 1,
88//! // mass_percent: 9.861401,
89//! // },
90//! // "H": Component {
91//! // chemical_element: Hydrogen,
92//! // atoms_count: 14,
93//! // mass_percent: 5.725739,
94//! // },
95//! // },
96//! // molar_mass: 246.466,
97//! // }
98//! ```
99//!
100//! ##### The parser grammar
101//!
102//! ```
103//! substance = coefficient? component+ hydrate?
104//! component = element | group
105//! group = '(' component+ ')' subscript?
106//! element = symbol subscript?
107//! hydrate = '*' coefficient? water
108//! symbol = uppercased | uppercased lowercased
109//! subscript = digit+
110//! coefficient = digit+
111//! water = 'H2O'
112//! uppercased = {'A'..'Z'}
113//! lowercased = {'a'..'z'}
114//! digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
115//! ```
116
117mod chemistry;
118mod compounds;
119mod error;
120mod parser;
121mod tokens;
122
123pub use chemistry::ChemicalElement;
124pub use compounds::{Component, Compound};
125pub use error::Error;
126use once_cell::sync::Lazy;
127use parser::Parser;
128pub use tokens::Element;
129
130static PERIODIC_TABLE: Lazy<chemistry::Table> = Lazy::new(|| chemistry::Table::new());
131
132/// A function takes raw formula string and produce compound or error
133pub fn parse<'a>(formula: impl Into<&'a str>) -> Result<Compound, Error> {
134 let mut parser = Parser::new(&PERIODIC_TABLE, formula.into());
135
136 let substance = parser.parse()?;
137
138 Ok(Compound::from(substance))
139}
140
141#[cfg(test)]
142mod tests {
143 use super::parse;
144 use crate::tokens::{Component, Element, Hydrate, Substance};
145 use crate::Compound;
146
147 #[test]
148 fn simple() {
149 let compound = parse("MgSO4*7H2O").unwrap();
150
151 assert_eq!(
152 compound,
153 Compound::from(Substance::from(
154 1,
155 vec![
156 Component::Element(Element::from("Mg", 1)),
157 Component::Element(Element::from("S", 1)),
158 Component::Element(Element::from("O", 4)),
159 ],
160 Some(Hydrate::from(
161 7,
162 vec![Element::from("H", 2), Element::from("O", 1),]
163 )),
164 ))
165 );
166 }
167}