use super::element_table::ELEMENTS;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Element {
pub z: u8,
pub symbol: &'static str,
pub name: &'static str,
pub mass: f64,
pub covalent_radius: f64,
pub atomic_radius: f64,
pub cpk: [u8; 3],
}
impl Element {
pub fn all() -> &'static [Element] {
&ELEMENTS
}
pub fn from_z(z: u8) -> Option<&'static Element> {
if z == 0 {
return None;
}
ELEMENTS.get(z as usize - 1)
}
pub fn from_symbol(symbol: &str) -> Option<&'static Element> {
let symbol = symbol.trim();
ELEMENTS
.iter()
.find(|e| e.symbol.eq_ignore_ascii_case(symbol))
}
pub fn from_label(label: &str) -> Option<&'static Element> {
let letters: String = label
.trim()
.chars()
.take_while(|c| c.is_ascii_alphabetic())
.collect();
if letters.is_empty() {
return None;
}
if letters.eq_ignore_ascii_case("D") || letters.eq_ignore_ascii_case("T") {
return Element::from_symbol("H");
}
let mut chars = letters.chars();
let first = chars.next()?.to_ascii_uppercase();
let second = chars.next().map(|c| c.to_ascii_lowercase());
if let Some(second) = second {
let two = format!("{first}{second}");
if let Some(e) = Element::from_symbol(&two) {
return Some(e);
}
}
Element::from_symbol(&first.to_string())
}
pub fn cpk_f32(&self) -> [f32; 3] {
[
self.cpk[0] as f32 / 255.0,
self.cpk[1] as f32 / 255.0,
self.cpk[2] as f32 / 255.0,
]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn labels_resolve_to_elements() {
assert_eq!(Element::from_label("Ru").unwrap().z, 44);
assert_eq!(Element::from_label("RuA").unwrap().z, 44);
assert_eq!(Element::from_label("Fe2+").unwrap().symbol, "Fe");
assert_eq!(Element::from_label("O1").unwrap().symbol, "O");
assert_eq!(Element::from_label("Co1").unwrap().symbol, "Co");
assert_eq!(Element::from_label("D").unwrap().symbol, "H");
assert!(Element::from_label("Xx").is_none());
assert!(Element::from_label("").is_none());
assert!(Element::from_label("1").is_none());
assert_eq!(Element::from_z(103).unwrap().symbol, "Lr");
assert!(Element::from_z(0).is_none());
}
}