Skip to main content

use_ion/
ion_charge.rs

1use std::fmt;
2
3use crate::{ChargeSign, IonValidationError};
4
5/// A nonzero ionic charge magnitude.
6#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
7pub struct ChargeMagnitude(u8);
8
9impl ChargeMagnitude {
10    /// Creates a charge magnitude.
11    ///
12    /// # Errors
13    ///
14    /// Returns [`IonValidationError::ZeroChargeMagnitude`] when `magnitude` is zero.
15    pub const fn new(magnitude: u8) -> Result<Self, IonValidationError> {
16        if magnitude == 0 {
17            Err(IonValidationError::ZeroChargeMagnitude)
18        } else {
19            Ok(Self(magnitude))
20        }
21    }
22
23    /// Returns the magnitude value.
24    #[must_use]
25    pub const fn get(self) -> u8 {
26        self.0
27    }
28}
29
30impl fmt::Display for ChargeMagnitude {
31    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
32        write!(formatter, "{}", self.0)
33    }
34}
35
36/// A nonzero signed ionic charge.
37#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
38pub struct IonCharge {
39    sign: ChargeSign,
40    magnitude: ChargeMagnitude,
41}
42
43impl IonCharge {
44    /// Creates a positive ion charge.
45    ///
46    /// # Errors
47    ///
48    /// Returns [`IonValidationError::ZeroChargeMagnitude`] when `magnitude` is zero.
49    pub const fn positive(magnitude: u8) -> Result<Self, IonValidationError> {
50        Ok(Self {
51            sign: ChargeSign::Positive,
52            magnitude: match ChargeMagnitude::new(magnitude) {
53                Ok(value) => value,
54                Err(error) => return Err(error),
55            },
56        })
57    }
58
59    /// Creates a negative ion charge.
60    ///
61    /// # Errors
62    ///
63    /// Returns [`IonValidationError::ZeroChargeMagnitude`] when `magnitude` is zero.
64    pub const fn negative(magnitude: u8) -> Result<Self, IonValidationError> {
65        Ok(Self {
66            sign: ChargeSign::Negative,
67            magnitude: match ChargeMagnitude::new(magnitude) {
68                Ok(value) => value,
69                Err(error) => return Err(error),
70            },
71        })
72    }
73
74    /// Returns the charge sign.
75    #[must_use]
76    pub const fn sign(self) -> ChargeSign {
77        self.sign
78    }
79
80    /// Returns the charge magnitude as a primitive value.
81    #[must_use]
82    pub const fn magnitude(self) -> u8 {
83        self.magnitude.get()
84    }
85
86    /// Returns the charge magnitude wrapper.
87    #[must_use]
88    pub const fn magnitude_value(self) -> ChargeMagnitude {
89        self.magnitude
90    }
91
92    /// Returns `true` for a positive charge.
93    #[must_use]
94    pub const fn is_positive(self) -> bool {
95        self.sign.is_positive()
96    }
97
98    /// Returns `true` for a negative charge.
99    #[must_use]
100    pub const fn is_negative(self) -> bool {
101        self.sign.is_negative()
102    }
103
104    /// Returns `true` for a cation charge.
105    #[must_use]
106    pub const fn is_cation(self) -> bool {
107        self.is_positive()
108    }
109
110    /// Returns `true` for an anion charge.
111    #[must_use]
112    pub const fn is_anion(self) -> bool {
113        self.is_negative()
114    }
115}
116
117impl fmt::Display for IonCharge {
118    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
119        if self.magnitude.get() == 1 {
120            write!(formatter, "{}", self.sign)
121        } else {
122            write!(formatter, "{}{}", self.magnitude, self.sign)
123        }
124    }
125}