1#[cfg(test)]
2use googletest::{Result as GtestResult, prelude::*};
3
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub(crate) struct IterationCount(u32);
6
7impl IterationCount {
8 pub(crate) const ONE: Self = Self(1);
9
10 #[must_use]
11 pub(crate) const fn get(self) -> u32 {
12 self.0
13 }
14}
15
16impl TryFrom<u32> for IterationCount {
17 type Error = RunParametersError;
18
19 fn try_from(value: u32) -> Result<Self, Self::Error> {
20 if value == 0 {
21 Err(RunParametersError::ZeroIterations)
22 } else {
23 Ok(Self(value))
24 }
25 }
26}
27
28#[derive(Clone, Copy, Debug, Eq, PartialEq)]
29pub(crate) struct FightDurationSeconds(u32);
30
31impl FightDurationSeconds {
32 pub(crate) const fn from_nonzero_const(value: u32) -> Self {
33 assert!(value > 0, "fight duration must be nonzero");
34
35 Self(value)
36 }
37
38 #[must_use]
39 pub(crate) const fn get(self) -> u32 {
40 self.0
41 }
42}
43
44impl TryFrom<u32> for FightDurationSeconds {
45 type Error = RunParametersError;
46
47 fn try_from(value: u32) -> Result<Self, Self::Error> {
48 if value == 0 {
49 Err(RunParametersError::ZeroDuration)
50 } else {
51 Ok(Self(value))
52 }
53 }
54}
55
56#[derive(Clone, Copy, Debug, Eq, PartialEq)]
57pub(crate) struct RunParameters {
58 iterations: IterationCount,
59 fight_duration: FightDurationSeconds,
60}
61
62impl RunParameters {
63 #[must_use]
64 pub(crate) const fn new(
65 iterations: IterationCount,
66 fight_duration: FightDurationSeconds,
67 ) -> Self {
68 Self {
69 iterations,
70 fight_duration,
71 }
72 }
73
74 #[must_use]
75 pub(crate) const fn iterations(self) -> u32 {
76 self.iterations.get()
77 }
78
79 #[must_use]
80 pub(crate) const fn fight_duration_secs(self) -> u32 {
81 self.fight_duration.get()
82 }
83}
84
85#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
86pub(crate) enum RunParametersError {
87 #[error("iterations must be greater than zero")]
88 ZeroIterations,
89 #[error("duration must be greater than zero")]
90 ZeroDuration,
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[gtest]
98 fn validated_parameters_preserve_both_domains() -> GtestResult<()> {
99 let parameters = RunParameters::new(
100 IterationCount::try_from(17).or_fail()?,
101 FightDurationSeconds::try_from(45).or_fail()?,
102 );
103
104 verify_that!(parameters.iterations(), eq(17))?;
105 verify_that!(parameters.fight_duration_secs(), eq(45))?;
106
107 Ok(())
108 }
109
110 #[gtest]
111 fn zero_values_report_their_exact_domain() -> GtestResult<()> {
112 verify_that!(
113 IterationCount::try_from(0),
114 eq(Err(RunParametersError::ZeroIterations))
115 )?;
116 verify_that!(
117 FightDurationSeconds::try_from(0),
118 eq(Err(RunParametersError::ZeroDuration))
119 )?;
120 verify_that!(
121 RunParametersError::ZeroIterations.to_string(),
122 eq("iterations must be greater than zero")
123 )?;
124 verify_that!(
125 RunParametersError::ZeroDuration.to_string(),
126 eq("duration must be greater than zero")
127 )?;
128
129 Ok(())
130 }
131}