use std::fmt;
use crate::{
OxidationMagnitude, OxidationSign, OxidationStateValidationError, RomanOxidationState,
};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct OxidationState {
sign: OxidationSign,
magnitude: OxidationMagnitude,
}
impl OxidationState {
pub const fn new(
sign: OxidationSign,
magnitude: OxidationMagnitude,
) -> Result<Self, OxidationStateValidationError> {
match (sign, magnitude.get()) {
(OxidationSign::Positive | OxidationSign::Negative, 0) => {
Err(OxidationStateValidationError::ZeroSignedMagnitude)
},
(OxidationSign::Zero, 0) => Ok(Self { sign, magnitude }),
(OxidationSign::Zero, _) => Err(OxidationStateValidationError::NonZeroZeroMagnitude),
_ => Ok(Self { sign, magnitude }),
}
}
pub fn positive(magnitude: u8) -> Result<Self, OxidationStateValidationError> {
let magnitude = OxidationMagnitude::new(magnitude)?;
Self::new(OxidationSign::Positive, magnitude)
}
pub fn negative(magnitude: u8) -> Result<Self, OxidationStateValidationError> {
let magnitude = OxidationMagnitude::new(magnitude)?;
Self::new(OxidationSign::Negative, magnitude)
}
#[must_use]
pub const fn zero() -> Self {
Self {
sign: OxidationSign::Zero,
magnitude: OxidationMagnitude::ZERO,
}
}
#[must_use]
pub const fn sign(self) -> OxidationSign {
self.sign
}
#[must_use]
pub const fn magnitude(self) -> OxidationMagnitude {
self.magnitude
}
#[must_use]
pub const fn magnitude_value(self) -> u8 {
self.magnitude.get()
}
#[must_use]
pub const fn signed_value(self) -> i8 {
match self.sign {
OxidationSign::Positive => self.magnitude.get() as i8,
OxidationSign::Negative => -(self.magnitude.get() as i8),
OxidationSign::Zero => 0,
}
}
#[must_use]
pub const fn is_positive(self) -> bool {
self.sign.is_positive()
}
#[must_use]
pub const fn is_negative(self) -> bool {
self.sign.is_negative()
}
#[must_use]
pub const fn is_zero(self) -> bool {
self.sign.is_zero()
}
#[must_use]
pub fn to_roman(self) -> Option<String> {
RomanOxidationState::from_state(self).map(|roman| roman.to_string())
}
}
impl Default for OxidationState {
fn default() -> Self {
Self::zero()
}
}
impl fmt::Display for OxidationState {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.sign {
OxidationSign::Positive => write!(formatter, "+{}", self.magnitude),
OxidationSign::Negative => write!(formatter, "-{}", self.magnitude),
OxidationSign::Zero => formatter.write_str("0"),
}
}
}