use std::fmt;
use use_chemical_formula::ChemicalFormula;
use crate::{IonCharge, IonFormula, IonKind, IonName, IonValidationError};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Ion {
formula: IonFormula,
charge: IonCharge,
name: Option<IonName>,
kinds: Vec<IonKind>,
oxidation_state_label: Option<String>,
}
impl Ion {
#[must_use]
pub fn new(formula: ChemicalFormula, charge: IonCharge) -> Self {
Self {
formula: IonFormula::new(formula),
charge,
name: None,
kinds: Vec::new(),
oxidation_state_label: None,
}
}
#[must_use]
pub fn formula(&self) -> &ChemicalFormula {
self.formula.as_formula()
}
#[must_use]
pub const fn ion_formula(&self) -> &IonFormula {
&self.formula
}
#[must_use]
pub const fn charge(&self) -> IonCharge {
self.charge
}
#[must_use]
pub const fn name(&self) -> Option<&IonName> {
self.name.as_ref()
}
#[must_use]
pub fn kinds(&self) -> &[IonKind] {
&self.kinds
}
#[must_use]
pub fn oxidation_state_label(&self) -> Option<&str> {
self.oxidation_state_label.as_deref()
}
#[must_use]
pub const fn is_cation(&self) -> bool {
self.charge.is_cation()
}
#[must_use]
pub const fn is_anion(&self) -> bool {
self.charge.is_anion()
}
#[must_use]
pub fn with_kind(mut self, kind: IonKind) -> Self {
if !self.kinds.contains(&kind) {
self.kinds.push(kind);
}
self
}
#[must_use]
pub fn with_name(mut self, name: IonName) -> Self {
self.name = Some(name);
self
}
pub fn try_with_name(self, name: &str) -> Result<Self, IonValidationError> {
Ok(self.with_name(IonName::new(name)?))
}
#[must_use]
pub fn with_oxidation_state_label(mut self, label: String) -> Self {
self.oxidation_state_label = Some(label);
self
}
pub fn try_with_oxidation_state_label(self, label: &str) -> Result<Self, IonValidationError> {
let trimmed = label.trim();
if trimmed.is_empty() {
Err(IonValidationError::EmptyOxidationStateLabel)
} else {
Ok(self.with_oxidation_state_label(trimmed.to_owned()))
}
}
}
impl fmt::Display for Ion {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.charge.magnitude() == 1 {
write!(formatter, "{}{}", self.formula, self.charge.sign())
} else {
write!(
formatter,
"{}^{}{}",
self.formula,
self.charge.magnitude(),
self.charge.sign()
)
}
}
}