use std::fmt;
use crate::{
Product, Reactant, ReactionArrow, ReactionCondition, ReactionConditionSet, ReactionEquation,
ReactionKind, ReactionValidationError,
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ChemicalReaction {
equation: ReactionEquation,
conditions: ReactionConditionSet,
kinds: Vec<ReactionKind>,
}
impl ChemicalReaction {
#[must_use]
pub const fn new() -> Self {
Self {
equation: ReactionEquation::new(),
conditions: ReactionConditionSet::new(),
kinds: Vec::new(),
}
}
#[must_use]
pub fn with_reactant<T>(mut self, reactant: T) -> Self
where
T: Into<Reactant>,
{
self.equation = self.equation.with_reactant(reactant);
self
}
#[must_use]
pub fn with_product<T>(mut self, product: T) -> Self
where
T: Into<Product>,
{
self.equation = self.equation.with_product(product);
self
}
#[must_use]
pub fn with_arrow(mut self, arrow: ReactionArrow) -> Self {
self.equation = self.equation.with_arrow(arrow);
self
}
#[must_use]
pub fn with_condition<T>(mut self, condition: T) -> Self
where
T: Into<ReactionCondition>,
{
self.conditions.push(condition);
self
}
#[must_use]
pub fn with_kind(mut self, kind: ReactionKind) -> Self {
if !self.kinds.contains(&kind) {
self.kinds.push(kind);
}
self
}
#[must_use]
pub const fn equation(&self) -> &ReactionEquation {
&self.equation
}
#[must_use]
pub fn reactants(&self) -> &[Reactant] {
self.equation.reactants()
}
#[must_use]
pub fn products(&self) -> &[Product] {
self.equation.products()
}
#[must_use]
pub const fn arrow(&self) -> ReactionArrow {
self.equation.arrow()
}
#[must_use]
pub const fn conditions(&self) -> &ReactionConditionSet {
&self.conditions
}
#[must_use]
pub fn kinds(&self) -> &[ReactionKind] {
&self.kinds
}
pub fn validate(&self) -> Result<(), ReactionValidationError> {
self.equation.validate()?;
self.conditions.validate()
}
}
impl Default for ChemicalReaction {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for ChemicalReaction {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}", self.equation)
}
}