1use std::fmt;
2
3#[derive(Copy, Clone, Debug, Default, PartialEq)]
11pub enum Domain {
12 #[default]
13 Real,
14 Integer,
15 Binary,
16 SemiContinuous {
17 threshold: f64,
18 },
19 SemiInteger {
20 threshold: f64,
21 },
22}
23
24impl fmt::Display for Domain {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 match self {
27 Self::Real => f.write_str("real"),
28 Self::Integer => f.write_str("integer"),
29 Self::Binary => f.write_str("binary"),
30 Self::SemiContinuous { threshold } => write!(f, "semi-continuous({threshold})"),
31 Self::SemiInteger { threshold } => write!(f, "semi-integer({threshold})"),
32 }
33 }
34}
35
36impl Domain {
37 #[must_use]
39 pub fn is_integer(self) -> bool {
40 matches!(self, Self::Integer | Self::Binary | Self::SemiInteger { .. })
41 }
42
43 #[must_use]
47 pub fn semi_threshold(self) -> Option<f64> {
48 match self {
49 Self::SemiContinuous { threshold } | Self::SemiInteger { threshold } => Some(threshold),
50 _ => None,
51 }
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::Domain;
58
59 #[test]
60 fn semi_threshold_only_for_semi_domains() {
61 assert_eq!(Domain::Real.semi_threshold(), None);
62 assert_eq!(Domain::Integer.semi_threshold(), None);
63 assert_eq!(Domain::Binary.semi_threshold(), None);
64 assert_eq!(Domain::SemiContinuous { threshold: 2.0 }.semi_threshold(), Some(2.0));
65 assert_eq!(Domain::SemiInteger { threshold: 1.0 }.semi_threshold(), Some(1.0));
66 }
67
68 #[test]
69 fn display_uses_user_facing_ascii_labels() {
70 let labels = [
71 Domain::Real.to_string(),
72 Domain::Integer.to_string(),
73 Domain::Binary.to_string(),
74 Domain::SemiContinuous { threshold: 3.0 }.to_string(),
75 Domain::SemiInteger { threshold: 2.5 }.to_string(),
76 ];
77 assert_eq!(
78 labels,
79 ["real", "integer", "binary", "semi-continuous(3)", "semi-integer(2.5)"]
80 );
81 assert!(labels.iter().all(|label| label.is_ascii()));
82 }
83
84 #[test]
85 fn default_domain_is_real() {
86 assert_eq!(Domain::default(), Domain::Real);
87 }
88
89 #[test]
90 fn integer_domains_are_integer() {
91 assert!(Domain::Integer.is_integer());
92 assert!(Domain::Binary.is_integer());
93 assert!(Domain::SemiInteger { threshold: 2.0 }.is_integer());
94 }
95
96 #[test]
97 fn non_integer_domains_are_not_integer() {
98 assert!(!Domain::Real.is_integer());
99 assert!(!Domain::SemiContinuous { threshold: 2.0 }.is_integer());
100 }
101}