use std::fmt;
use crate::{AtomLabel, MoleculeValidationError};
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct MolecularAtomId(String);
impl MolecularAtomId {
pub fn new(id: &str) -> Result<Self, MoleculeValidationError> {
let trimmed = id.trim();
if trimmed.is_empty() {
Err(MoleculeValidationError::EmptyAtomId)
} else {
Ok(Self(trimmed.to_owned()))
}
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn into_string(self) -> String {
self.0
}
}
impl AsRef<str> for MolecularAtomId {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl TryFrom<&str> for MolecularAtomId {
type Error = MoleculeValidationError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::new(value)
}
}
impl fmt::Display for MolecularAtomId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MolecularAtom {
label: AtomLabel,
id: Option<MolecularAtomId>,
}
impl MolecularAtom {
pub fn new(label: &str) -> Result<Self, MoleculeValidationError> {
Ok(Self {
label: AtomLabel::new(label)?,
id: None,
})
}
#[must_use]
pub const fn label(&self) -> &AtomLabel {
&self.label
}
#[must_use]
pub const fn id(&self) -> Option<&MolecularAtomId> {
self.id.as_ref()
}
#[must_use]
pub fn with_id(mut self, id: MolecularAtomId) -> Self {
self.id = Some(id);
self
}
pub fn try_with_id(self, id: &str) -> Result<Self, MoleculeValidationError> {
Ok(self.with_id(MolecularAtomId::new(id)?))
}
}
impl fmt::Display for MolecularAtom {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.id {
Some(id) => write!(formatter, "{}#{id}", self.label),
None => write!(formatter, "{}", self.label),
}
}
}