use_reaction/
reaction_equation.rs1use std::fmt;
2
3use crate::{Product, Reactant, ReactionArrow, ReactionValidationError};
4
5#[derive(Clone, Debug, Eq, PartialEq)]
7pub struct ReactionEquation {
8 reactants: Vec<Reactant>,
9 products: Vec<Product>,
10 arrow: ReactionArrow,
11}
12
13impl ReactionEquation {
14 #[must_use]
16 pub const fn new() -> Self {
17 Self {
18 reactants: Vec::new(),
19 products: Vec::new(),
20 arrow: ReactionArrow::Forward,
21 }
22 }
23
24 #[must_use]
26 pub fn with_reactant<T>(mut self, reactant: T) -> Self
27 where
28 T: Into<Reactant>,
29 {
30 self.reactants.push(reactant.into());
31 self
32 }
33
34 #[must_use]
36 pub fn with_product<T>(mut self, product: T) -> Self
37 where
38 T: Into<Product>,
39 {
40 self.products.push(product.into());
41 self
42 }
43
44 #[must_use]
46 pub const fn with_arrow(mut self, arrow: ReactionArrow) -> Self {
47 self.arrow = arrow;
48 self
49 }
50
51 #[must_use]
53 pub fn reactants(&self) -> &[Reactant] {
54 &self.reactants
55 }
56
57 #[must_use]
59 pub fn products(&self) -> &[Product] {
60 &self.products
61 }
62
63 #[must_use]
65 pub const fn arrow(&self) -> ReactionArrow {
66 self.arrow
67 }
68
69 pub fn validate(&self) -> Result<(), ReactionValidationError> {
77 match (self.reactants.is_empty(), self.products.is_empty()) {
78 (true, true) => Err(ReactionValidationError::EmptyReaction),
79 (true, false) => Err(ReactionValidationError::MissingReactants),
80 (false, true) => Err(ReactionValidationError::MissingProducts),
81 (false, false) => Ok(()),
82 }
83 }
84}
85
86impl Default for ReactionEquation {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92impl fmt::Display for ReactionEquation {
93 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
94 write_side(formatter, &self.reactants)?;
95 write!(formatter, " {} ", self.arrow)?;
96 write_side(formatter, &self.products)
97 }
98}
99
100fn write_side<T>(formatter: &mut fmt::Formatter<'_>, terms: &[T]) -> fmt::Result
101where
102 T: fmt::Display,
103{
104 for (index, term) in terms.iter().enumerate() {
105 if index > 0 {
106 formatter.write_str(" + ")?;
107 }
108 write!(formatter, "{term}")?;
109 }
110
111 Ok(())
112}