use_chemical_formula/
element_symbol.rs1use std::fmt;
2
3use crate::FormulaValidationError;
4
5#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
7pub struct ElementSymbol(String);
8
9impl ElementSymbol {
10 pub fn new(symbol: &str) -> Result<Self, FormulaValidationError> {
17 if is_valid_element_symbol(symbol) {
18 Ok(Self(symbol.to_owned()))
19 } else {
20 Err(FormulaValidationError::InvalidSymbol(symbol.to_owned()))
21 }
22 }
23
24 #[must_use]
26 pub fn as_str(&self) -> &str {
27 &self.0
28 }
29
30 #[must_use]
32 pub fn into_string(self) -> String {
33 self.0
34 }
35}
36
37impl AsRef<str> for ElementSymbol {
38 fn as_ref(&self) -> &str {
39 self.as_str()
40 }
41}
42
43impl TryFrom<&str> for ElementSymbol {
44 type Error = FormulaValidationError;
45
46 fn try_from(value: &str) -> Result<Self, Self::Error> {
47 Self::new(value)
48 }
49}
50
51impl fmt::Display for ElementSymbol {
52 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
53 formatter.write_str(self.as_str())
54 }
55}
56
57#[must_use]
59pub fn is_valid_element_symbol(symbol: &str) -> bool {
60 let mut characters = symbol.chars();
61 let Some(first) = characters.next() else {
62 return false;
63 };
64
65 if !first.is_ascii_uppercase() {
66 return false;
67 }
68
69 match characters.next() {
70 None => true,
71 Some(second) if second.is_ascii_lowercase() => characters.next().is_none(),
72 Some(_) => false,
73 }
74}