nil_core/infrastructure/building/
level.rs1use derive_more::{Deref, Into};
5use nil_util::F64Math;
6use serde::{Deserialize, Serialize};
7use std::cmp;
8use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
9
10#[derive(Copy, Debug, Deref, derive_more::Display, Into, Hash, Deserialize, Serialize, F64Math)]
11#[derive_const(Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
12#[into(i16, i32, u8, u16, u64, usize)]
13#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
14pub struct BuildingLevel(u8);
15
16impl BuildingLevel {
17 pub const ZERO: BuildingLevel = BuildingLevel(0);
18
19 #[inline]
20 pub const fn new(level: u8) -> Self {
21 Self(level)
22 }
23}
24
25impl const From<BuildingLevel> for i8 {
26 fn from(value: BuildingLevel) -> Self {
27 debug_assert!(i8::try_from(value.0).is_ok());
28 i8::try_from(value.0).unwrap_or(i8::MAX)
29 }
30}
31
32impl const From<BuildingLevel> for u32 {
33 fn from(value: BuildingLevel) -> Self {
34 u32::from(value.0)
35 }
36}
37
38impl const From<BuildingLevel> for f64 {
39 fn from(value: BuildingLevel) -> Self {
40 f64::from(value.0)
41 }
42}
43
44impl const PartialEq<u8> for BuildingLevel {
45 fn eq(&self, other: &u8) -> bool {
46 self.0.eq(other)
47 }
48}
49
50impl const PartialEq<BuildingLevel> for u8 {
51 fn eq(&self, other: &BuildingLevel) -> bool {
52 self.eq(&other.0)
53 }
54}
55
56impl const PartialEq<f64> for BuildingLevel {
57 fn eq(&self, other: &f64) -> bool {
58 f64::from(self.0).eq(other)
59 }
60}
61
62impl const PartialEq<BuildingLevel> for f64 {
63 fn eq(&self, other: &BuildingLevel) -> bool {
64 self.eq(&f64::from(other.0))
65 }
66}
67
68impl const PartialOrd<u8> for BuildingLevel {
69 fn partial_cmp(&self, other: &u8) -> Option<cmp::Ordering> {
70 self.0.partial_cmp(other)
71 }
72}
73
74impl const PartialOrd<BuildingLevel> for u8 {
75 fn partial_cmp(&self, other: &BuildingLevel) -> Option<cmp::Ordering> {
76 self.partial_cmp(&other.0)
77 }
78}
79
80impl const PartialOrd<f64> for BuildingLevel {
81 fn partial_cmp(&self, other: &f64) -> Option<cmp::Ordering> {
82 f64::from(self.0).partial_cmp(other)
83 }
84}
85
86impl const PartialOrd<BuildingLevel> for f64 {
87 fn partial_cmp(&self, other: &BuildingLevel) -> Option<cmp::Ordering> {
88 self.partial_cmp(&f64::from(other.0))
89 }
90}
91
92impl const Add for BuildingLevel {
93 type Output = Self;
94
95 fn add(self, rhs: Self) -> Self {
96 Self(self.0.saturating_add(rhs.0))
97 }
98}
99
100impl const Add<u8> for BuildingLevel {
101 type Output = Self;
102
103 fn add(self, rhs: u8) -> Self {
104 Self(self.0.saturating_add(rhs))
105 }
106}
107
108impl const Add<i8> for BuildingLevel {
109 type Output = Self;
110
111 fn add(self, rhs: i8) -> Self {
112 Self(self.0.saturating_add_signed(rhs))
113 }
114}
115
116impl const Add<BuildingLevelDiff> for BuildingLevel {
117 type Output = Self;
118
119 fn add(self, rhs: BuildingLevelDiff) -> Self {
120 self + rhs.0
121 }
122}
123
124impl const AddAssign for BuildingLevel {
125 fn add_assign(&mut self, rhs: Self) {
126 *self = *self + rhs;
127 }
128}
129
130impl const AddAssign<u8> for BuildingLevel {
131 fn add_assign(&mut self, rhs: u8) {
132 *self = *self + rhs;
133 }
134}
135
136impl const AddAssign<i8> for BuildingLevel {
137 fn add_assign(&mut self, rhs: i8) {
138 *self = *self + rhs;
139 }
140}
141
142impl const AddAssign<BuildingLevelDiff> for BuildingLevel {
143 fn add_assign(&mut self, rhs: BuildingLevelDiff) {
144 *self = *self + rhs;
145 }
146}
147
148impl const Sub for BuildingLevel {
149 type Output = Self;
150
151 fn sub(self, rhs: Self) -> Self {
152 Self(self.0.saturating_sub(rhs.0))
153 }
154}
155
156impl const Sub<u8> for BuildingLevel {
157 type Output = Self;
158
159 fn sub(self, rhs: u8) -> Self {
160 Self(self.0.saturating_sub(rhs))
161 }
162}
163
164impl const Sub<i8> for BuildingLevel {
165 type Output = Self;
166
167 fn sub(self, rhs: i8) -> Self {
168 Self(self.0.saturating_sub_signed(rhs))
169 }
170}
171
172impl const Sub<BuildingLevelDiff> for BuildingLevel {
173 type Output = Self;
174
175 fn sub(self, rhs: BuildingLevelDiff) -> Self {
176 self - rhs.0
177 }
178}
179
180impl const SubAssign for BuildingLevel {
181 fn sub_assign(&mut self, rhs: Self) {
182 *self = *self - rhs;
183 }
184}
185
186impl const SubAssign<u8> for BuildingLevel {
187 fn sub_assign(&mut self, rhs: u8) {
188 *self = *self - rhs;
189 }
190}
191
192impl const SubAssign<i8> for BuildingLevel {
193 fn sub_assign(&mut self, rhs: i8) {
194 *self = *self - rhs;
195 }
196}
197
198impl const SubAssign<BuildingLevelDiff> for BuildingLevel {
199 fn sub_assign(&mut self, rhs: BuildingLevelDiff) {
200 *self = *self - rhs;
201 }
202}
203
204impl const Neg for BuildingLevel {
205 type Output = BuildingLevelDiff;
206
207 fn neg(self) -> BuildingLevelDiff {
208 BuildingLevelDiff::new(i8::from(self).neg())
209 }
210}
211
212#[derive(Clone, Copy, Debug, Deref, derive_more::Display, Into, Hash, Deserialize, Serialize)]
213#[derive_const(Default, PartialEq, Eq, PartialOrd, Ord)]
214#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
215pub struct BuildingLevelDiff(i8);
216
217impl BuildingLevelDiff {
218 pub const ZERO: BuildingLevelDiff = BuildingLevelDiff(0);
219
220 #[inline]
221 pub const fn new(level_diff: i8) -> Self {
222 Self(level_diff)
223 }
224}
225
226impl const From<f64> for BuildingLevelDiff {
227 fn from(mut value: f64) -> Self {
228 value = value.round();
229 debug_assert!(value.is_finite());
230 debug_assert!(value >= f64::from(i8::MIN));
231 debug_assert!(value <= f64::from(i8::MAX));
232 Self::new(value as i8)
233 }
234}
235
236impl const PartialEq<i8> for BuildingLevelDiff {
237 fn eq(&self, other: &i8) -> bool {
238 self.0.eq(other)
239 }
240}
241
242impl const PartialOrd<i8> for BuildingLevelDiff {
243 fn partial_cmp(&self, other: &i8) -> Option<cmp::Ordering> {
244 self.0.partial_cmp(other)
245 }
246}
247
248#[macro_export]
250macro_rules! lv {
251 ($level:expr) => {
252 const { $crate::infrastructure::building::level::BuildingLevel::new($level) }
253 };
254}
255
256#[macro_export]
258macro_rules! with_random_level {
259 ($building:ident) => {{ $crate::infrastructure::prelude::$building::with_random_level() }};
260 ($building:ident, $max:expr) => {{
261 $crate::infrastructure::prelude::$building::with_random_level_in()
262 .max($crate::lv!($max))
263 .call()
264 }};
265 ($building:ident, $min:expr, $max:expr) => {{
266 $crate::infrastructure::prelude::$building::with_random_level_in()
267 .min($crate::lv!($min))
268 .max($crate::lv!($max))
269 .call()
270 }};
271}