use_stoichiometry/
yield.rs1use std::fmt;
2
3use crate::StoichiometryValidationError;
4
5#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
7pub struct TheoreticalYield(f64);
8
9impl TheoreticalYield {
10 pub fn new(value: f64) -> Result<Self, StoichiometryValidationError> {
18 validate_finite_yield(value)?;
19
20 if value <= 0.0 {
21 Err(StoichiometryValidationError::NonPositiveTheoreticalYield)
22 } else {
23 Ok(Self(value))
24 }
25 }
26
27 #[must_use]
29 pub const fn value(self) -> f64 {
30 self.0
31 }
32}
33
34impl fmt::Display for TheoreticalYield {
35 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
36 write!(formatter, "{}", self.0)
37 }
38}
39
40#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
42pub struct ActualYield(f64);
43
44impl ActualYield {
45 pub fn new(value: f64) -> Result<Self, StoichiometryValidationError> {
52 validate_nonnegative_yield(value).map(Self)
53 }
54
55 #[must_use]
57 pub const fn value(self) -> f64 {
58 self.0
59 }
60}
61
62impl fmt::Display for ActualYield {
63 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
64 write!(formatter, "{}", self.0)
65 }
66}
67
68#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
70pub struct PercentYield(f64);
71
72impl PercentYield {
73 pub fn new(value: f64) -> Result<Self, StoichiometryValidationError> {
80 validate_nonnegative_yield(value).map(Self)
81 }
82
83 pub fn from_actual_and_theoretical(
90 actual: f64,
91 theoretical: f64,
92 ) -> Result<Self, StoichiometryValidationError> {
93 Self::from_yields(
94 ActualYield::new(actual)?,
95 TheoreticalYield::new(theoretical)?,
96 )
97 }
98
99 pub fn from_yields(
106 actual: ActualYield,
107 theoretical: TheoreticalYield,
108 ) -> Result<Self, StoichiometryValidationError> {
109 Self::new((actual.value() / theoretical.value()) * 100.0)
110 }
111
112 #[must_use]
114 pub const fn value(self) -> f64 {
115 self.0
116 }
117}
118
119impl fmt::Display for PercentYield {
120 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
121 write!(formatter, "{}%", self.0)
122 }
123}
124
125fn validate_finite_yield(value: f64) -> Result<(), StoichiometryValidationError> {
126 if value.is_finite() {
127 Ok(())
128 } else {
129 Err(StoichiometryValidationError::NonFiniteYield)
130 }
131}
132
133fn validate_nonnegative_yield(value: f64) -> Result<f64, StoichiometryValidationError> {
134 validate_finite_yield(value)?;
135
136 if value < 0.0 {
137 Err(StoichiometryValidationError::NegativeYield)
138 } else {
139 Ok(value)
140 }
141}