use use_chemical_formula::ChemicalFormula;
use crate::{
AtomConnection, MolecularAtom, Molecule, MoleculeCharge, MoleculeKind, MoleculeValidationError,
};
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct MoleculeBuilder {
name: String,
formula: Option<ChemicalFormula>,
atoms: Vec<MolecularAtom>,
connections: Vec<AtomConnection>,
charge: MoleculeCharge,
kinds: Vec<MoleculeKind>,
}
impl MoleculeBuilder {
#[must_use]
pub fn new(name: &str) -> Self {
Self {
name: name.to_owned(),
formula: None,
atoms: Vec::new(),
connections: Vec::new(),
charge: MoleculeCharge::NEUTRAL,
kinds: Vec::new(),
}
}
#[must_use]
pub fn formula(mut self, formula: ChemicalFormula) -> Self {
self.formula = Some(formula);
self
}
#[must_use]
pub fn atom(mut self, atom: MolecularAtom) -> Self {
self.atoms.push(atom);
self
}
#[must_use]
pub fn connection(mut self, connection: AtomConnection) -> Self {
self.connections.push(connection);
self
}
#[must_use]
pub const fn charge(mut self, charge: MoleculeCharge) -> Self {
self.charge = charge;
self
}
#[must_use]
pub fn kind(mut self, kind: MoleculeKind) -> Self {
if !self.kinds.contains(&kind) {
self.kinds.push(kind);
}
self
}
pub fn build(self) -> Result<Molecule, MoleculeValidationError> {
let Some(formula) = self.formula else {
return Err(MoleculeValidationError::MissingFormula);
};
let mut molecule = Molecule::new(&self.name, formula)?.with_charge(self.charge);
for kind in self.kinds {
molecule = molecule.with_kind(kind);
}
for atom in self.atoms {
molecule = molecule.with_atom(atom);
}
for connection in self.connections {
molecule = molecule.try_with_connection(connection)?;
}
Ok(molecule)
}
}