use_oxidation_state/
oxidation_state.rs1use std::fmt;
2
3use crate::{
4 OxidationMagnitude, OxidationSign, OxidationStateValidationError, RomanOxidationState,
5};
6
7#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
9pub struct OxidationState {
10 sign: OxidationSign,
11 magnitude: OxidationMagnitude,
12}
13
14impl OxidationState {
15 pub const fn new(
24 sign: OxidationSign,
25 magnitude: OxidationMagnitude,
26 ) -> Result<Self, OxidationStateValidationError> {
27 match (sign, magnitude.get()) {
28 (OxidationSign::Positive | OxidationSign::Negative, 0) => {
29 Err(OxidationStateValidationError::ZeroSignedMagnitude)
30 },
31 (OxidationSign::Zero, 0) => Ok(Self { sign, magnitude }),
32 (OxidationSign::Zero, _) => Err(OxidationStateValidationError::NonZeroZeroMagnitude),
33 _ => Ok(Self { sign, magnitude }),
34 }
35 }
36
37 pub fn positive(magnitude: u8) -> Result<Self, OxidationStateValidationError> {
45 let magnitude = OxidationMagnitude::new(magnitude)?;
46
47 Self::new(OxidationSign::Positive, magnitude)
48 }
49
50 pub fn negative(magnitude: u8) -> Result<Self, OxidationStateValidationError> {
58 let magnitude = OxidationMagnitude::new(magnitude)?;
59
60 Self::new(OxidationSign::Negative, magnitude)
61 }
62
63 #[must_use]
65 pub const fn zero() -> Self {
66 Self {
67 sign: OxidationSign::Zero,
68 magnitude: OxidationMagnitude::ZERO,
69 }
70 }
71
72 #[must_use]
74 pub const fn sign(self) -> OxidationSign {
75 self.sign
76 }
77
78 #[must_use]
80 pub const fn magnitude(self) -> OxidationMagnitude {
81 self.magnitude
82 }
83
84 #[must_use]
86 pub const fn magnitude_value(self) -> u8 {
87 self.magnitude.get()
88 }
89
90 #[must_use]
92 pub const fn signed_value(self) -> i8 {
93 match self.sign {
94 OxidationSign::Positive => self.magnitude.get() as i8,
95 OxidationSign::Negative => -(self.magnitude.get() as i8),
96 OxidationSign::Zero => 0,
97 }
98 }
99
100 #[must_use]
102 pub const fn is_positive(self) -> bool {
103 self.sign.is_positive()
104 }
105
106 #[must_use]
108 pub const fn is_negative(self) -> bool {
109 self.sign.is_negative()
110 }
111
112 #[must_use]
114 pub const fn is_zero(self) -> bool {
115 self.sign.is_zero()
116 }
117
118 #[must_use]
120 pub fn to_roman(self) -> Option<String> {
121 RomanOxidationState::from_state(self).map(|roman| roman.to_string())
122 }
123}
124
125impl Default for OxidationState {
126 fn default() -> Self {
127 Self::zero()
128 }
129}
130
131impl fmt::Display for OxidationState {
132 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
133 match self.sign {
134 OxidationSign::Positive => write!(formatter, "+{}", self.magnitude),
135 OxidationSign::Negative => write!(formatter, "-{}", self.magnitude),
136 OxidationSign::Zero => formatter.write_str("0"),
137 }
138 }
139}