use crate::element::Element;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Chirality {
#[default]
None,
CounterClockwise,
Clockwise,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CipCode {
R,
S,
E,
Z,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Atom {
pub element: Element,
pub isotope: Option<u16>,
pub charge: i8,
pub hydrogen_count: Option<u8>,
pub aromatic: bool,
pub chirality: Chirality,
pub wildcard: bool,
pub atom_map: Option<u16>,
pub cip_code: Option<CipCode>,
}
impl Atom {
pub fn new(element: Element) -> Self {
Self {
element,
isotope: None,
charge: 0,
hydrogen_count: None,
aromatic: false,
chirality: Chirality::None,
wildcard: false,
atom_map: None,
cip_code: None,
}
}
pub fn organic(element: Element) -> Self {
Self::new(element)
}
pub fn aromatic(element: Element) -> Self {
Self {
aromatic: true,
..Self::new(element)
}
}
pub fn bracket(
element: Element,
isotope: Option<u16>,
chirality: Chirality,
hydrogen_count: u8,
charge: i8,
atom_map: Option<u16>,
) -> Self {
Self {
element,
isotope,
charge,
hydrogen_count: Some(hydrogen_count),
aromatic: false,
chirality,
wildcard: false,
atom_map,
cip_code: None,
}
}
pub fn wildcard() -> Self {
Self {
element: Element::C,
wildcard: true,
hydrogen_count: Some(0),
..Self::new(Element::C)
}
}
pub fn explicit_hcount(&self) -> Option<u8> {
self.hydrogen_count
}
}
impl core::fmt::Display for Atom {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if self.wildcard {
return write!(f, "*");
}
let symbol = if self.aromatic {
self.element.symbol().to_lowercase()
} else {
self.element.symbol().to_string()
};
match self.isotope {
Some(iso) => write!(f, "[{iso}{symbol}]"),
None => write!(f, "{symbol}"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_atom_new() {
let a = Atom::new(Element::C);
assert_eq!(a.element, Element::C);
assert_eq!(a.charge, 0);
assert!(!a.aromatic);
assert!(!a.wildcard);
assert_eq!(a.hydrogen_count, None);
}
#[test]
fn test_aromatic_atom() {
let a = Atom::aromatic(Element::C);
assert!(a.aromatic);
}
#[test]
fn test_wildcard_atom() {
let a = Atom::wildcard();
assert!(a.wildcard);
assert_eq!(format!("{a}"), "*");
}
}