1use std::{
2 str::FromStr,
3 fmt::{self, Write},
4};
5use crate::{AcesError, AcesErrorKind};
6
7#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[repr(transparent)]
12pub struct Multiplicity(u64);
13
14impl Multiplicity {
15 #[inline]
16 pub const fn omega() -> Self {
17 Multiplicity(u64::max_value())
18 }
19
20 pub fn finite(value: u64) -> Option<Self> {
21 if value < u64::max_value() {
22 Some(Multiplicity(value))
23 } else {
24 None
25 }
26 }
27
28 #[inline]
29 pub const fn zero() -> Self {
30 Multiplicity(0)
31 }
32
33 #[inline]
34 pub const fn one() -> Self {
35 Multiplicity(1)
36 }
37
38 #[inline]
39 pub fn is_omega(self) -> bool {
40 self.0 == u64::max_value()
41 }
42
43 #[inline]
44 pub fn is_zero(self) -> bool {
45 self.0 == 0
46 }
47
48 #[inline]
49 pub fn is_finite(self) -> bool {
50 self.0 < u64::max_value()
51 }
52
53 #[inline]
54 pub fn is_positive(self) -> bool {
55 self.0 > 0
56 }
57
58 pub fn checked_add(self, other: Self) -> Option<Self> {
59 if self.0 == u64::max_value() {
60 Some(self)
61 } else if other.0 == u64::max_value() {
62 Some(other)
63 } else {
64 self.0.checked_add(other.0).and_then(|result| {
65 if result == u64::max_value() {
66 None
67 } else {
68 Some(Multiplicity(result))
69 }
70 })
71 }
72 }
73
74 pub fn checked_sub(self, other: Self) -> Option<Self> {
75 if self.0 == u64::max_value() {
76 Some(self)
77 } else if other.0 == u64::max_value() {
78 if self.0 == 0 {
79 Some(self)
80 } else {
81 None
82 }
83 } else {
84 self.0.checked_sub(other.0).map(Multiplicity)
85 }
86 }
87
88 pub fn saturating_add(self, other: Self) -> Self {
93 if self.0 == u64::max_value() {
94 self
95 } else {
96 let result = self.0.saturating_add(other.0);
97
98 if result == u64::max_value() {
99 Multiplicity(u64::max_value() - 1)
100 } else {
101 Multiplicity(result)
102 }
103 }
104 }
105
106 pub fn saturating_sub(self, other: Self) -> Self {
111 if self.0 == u64::max_value() {
112 self
113 } else if other.0 == u64::max_value() {
114 if self.0 == 0 {
115 self
116 } else {
117 Multiplicity(0)
118 }
119 } else {
120 let result = self.0.saturating_sub(other.0);
121
122 Multiplicity(result)
123 }
124 }
125}
126
127impl fmt::Debug for Multiplicity {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 write!(f, "Multiplicity({})", self)
130 }
131}
132
133impl fmt::Display for Multiplicity {
134 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135 if self.is_finite() {
136 self.0.fmt(f)
137 } else {
138 f.write_char('ω')
139 }
140 }
141}
142
143impl FromStr for Multiplicity {
144 type Err = AcesError;
145
146 fn from_str(s: &str) -> Result<Self, Self::Err> {
147 if s.eq_ignore_ascii_case("omega") || s == "ω" || s == "Ω" {
148 Ok(Multiplicity::omega())
149 } else {
150 match s.parse::<u64>() {
151 Ok(value) => Multiplicity::finite(value).ok_or_else(|| {
152 AcesError::from(AcesErrorKind::MultiplicityOverflow("parsing".into()))
153 }),
154 Err(err) => Err(AcesError::from(AcesErrorKind::from(err))),
155 }
156 }
157 }
158}
159
160pub type Capacity = Multiplicity;
166
167pub type Weight = Multiplicity;