use std::fmt;
use use_chemical_formula::ChemicalFormula;
use crate::{
AtomConnection, AtomCount, MolecularAtom, MolecularFormula, MoleculeBuilder, MoleculeCharge,
MoleculeKind, MoleculeName, MoleculeValidationError,
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Molecule {
name: MoleculeName,
formula: MolecularFormula,
atoms: Vec<MolecularAtom>,
connections: Vec<AtomConnection>,
charge: MoleculeCharge,
kinds: Vec<MoleculeKind>,
}
impl Molecule {
pub fn new(name: &str, formula: ChemicalFormula) -> Result<Self, MoleculeValidationError> {
Ok(Self {
name: MoleculeName::new(name)?,
formula: MolecularFormula::new(formula),
atoms: Vec::new(),
connections: Vec::new(),
charge: MoleculeCharge::NEUTRAL,
kinds: Vec::new(),
})
}
#[must_use]
pub fn builder(name: &str) -> MoleculeBuilder {
MoleculeBuilder::new(name)
}
#[must_use]
pub const fn name(&self) -> &MoleculeName {
&self.name
}
#[must_use]
pub fn formula(&self) -> &ChemicalFormula {
self.formula.as_formula()
}
#[must_use]
pub const fn molecular_formula(&self) -> &MolecularFormula {
&self.formula
}
#[must_use]
pub fn atoms(&self) -> &[MolecularAtom] {
&self.atoms
}
#[must_use]
pub fn atom_count(&self) -> usize {
self.atoms.len()
}
#[must_use]
pub fn atom_count_value(&self) -> AtomCount {
AtomCount::new(self.atom_count())
}
#[must_use]
pub fn connections(&self) -> &[AtomConnection] {
&self.connections
}
#[must_use]
pub const fn charge(&self) -> MoleculeCharge {
self.charge
}
#[must_use]
pub fn kinds(&self) -> &[MoleculeKind] {
&self.kinds
}
#[must_use]
pub fn with_kind(mut self, kind: MoleculeKind) -> Self {
if !self.kinds.contains(&kind) {
self.kinds.push(kind);
}
self
}
#[must_use]
pub const fn with_charge(mut self, charge: MoleculeCharge) -> Self {
self.charge = charge;
self
}
#[must_use]
pub fn with_atom(mut self, atom: MolecularAtom) -> Self {
self.atoms.push(atom);
self
}
pub fn try_with_connection(
mut self,
connection: AtomConnection,
) -> Result<Self, MoleculeValidationError> {
let connection = connection.validate_indices(self.atoms.len())?;
if !self.connections.contains(&connection) {
self.connections.push(connection);
}
Ok(self)
}
}
impl fmt::Display for Molecule {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{} ({})", self.name, self.formula)
}
}