use_oxidation_state/
element_oxidation_state.rs1use std::fmt;
2
3use crate::{OxidationState, OxidationStateValidationError};
4
5#[derive(Clone, Debug, Eq, Hash, PartialEq)]
7pub struct ElementOxidationState {
8 element_symbol: String,
9 state: OxidationState,
10}
11
12impl ElementOxidationState {
13 pub fn new(
22 element_symbol: &str,
23 state: OxidationState,
24 ) -> Result<Self, OxidationStateValidationError> {
25 let element_symbol = validate_element_symbol(element_symbol)?;
26
27 Ok(Self {
28 element_symbol,
29 state,
30 })
31 }
32
33 #[must_use]
35 pub fn element_symbol(&self) -> &str {
36 &self.element_symbol
37 }
38
39 #[must_use]
41 pub const fn state(&self) -> OxidationState {
42 self.state
43 }
44
45 #[must_use]
47 pub fn into_parts(self) -> (String, OxidationState) {
48 (self.element_symbol, self.state)
49 }
50}
51
52impl fmt::Display for ElementOxidationState {
53 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
54 if self.state.is_positive() {
55 if let Some(roman) = self.state.to_roman() {
56 write!(formatter, "{}({roman})", self.element_symbol)
57 } else {
58 write!(formatter, "{}({})", self.element_symbol, self.state)
59 }
60 } else {
61 write!(formatter, "{}({})", self.element_symbol, self.state)
62 }
63 }
64}
65
66fn validate_element_symbol(symbol: &str) -> Result<String, OxidationStateValidationError> {
67 let symbol = symbol.trim();
68
69 if symbol.is_empty() {
70 return Err(OxidationStateValidationError::EmptyElementSymbol);
71 }
72
73 if is_valid_element_symbol(symbol) {
74 Ok(symbol.to_owned())
75 } else {
76 Err(OxidationStateValidationError::InvalidElementSymbol(
77 symbol.to_owned(),
78 ))
79 }
80}
81
82fn is_valid_element_symbol(symbol: &str) -> bool {
83 let mut characters = symbol.chars();
84 let Some(first) = characters.next() else {
85 return false;
86 };
87
88 if !first.is_ascii_uppercase() {
89 return false;
90 }
91
92 match characters.next() {
93 None => true,
94 Some(second) if second.is_ascii_lowercase() => characters.next().is_none(),
95 Some(_) => false,
96 }
97}