nil_core/resources/
maintenance.rs1use super::Food;
5use super::diff::FoodDiff;
6use crate::military::army::Army;
7use crate::military::army::personnel::ArmyPersonnel;
8use crate::military::squad::Squad;
9use crate::military::unit::UnitChunkSize;
10use derive_more::Display;
11use nil_util::ConstDeref;
12use serde::{Deserialize, Serialize};
13use std::cmp::Ordering;
14use std::iter::Sum;
15use std::num::NonZeroU32;
16use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
17
18#[derive(Copy, Debug, Display, Deserialize, Serialize, ConstDeref)]
24#[derive_const(Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
25#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
26pub struct Maintenance(Food);
27
28impl Maintenance {
29 #[inline]
30 pub const fn new(value: u32) -> Self {
31 Self(Food::new(value))
32 }
33}
34
35const impl From<u32> for Maintenance {
36 fn from(value: u32) -> Self {
37 Self::new(value)
38 }
39}
40
41const impl From<Maintenance> for u32 {
42 fn from(value: Maintenance) -> Self {
43 u32::from(value.0)
44 }
45}
46
47const impl From<f64> for Maintenance {
48 fn from(value: f64) -> Self {
49 debug_assert!(value.is_finite());
50 Self::new(value as u32)
51 }
52}
53
54const impl From<Maintenance> for f64 {
55 fn from(value: Maintenance) -> Self {
56 f64::from(value.0)
57 }
58}
59
60impl<'a> Sum<&'a Squad> for Maintenance {
61 fn sum<I>(iter: I) -> Self
62 where
63 I: Iterator<Item = &'a Squad>,
64 {
65 iter.fold(Maintenance::default(), |acc, squad| {
66 acc + squad.maintenance()
67 })
68 }
69}
70
71impl<'a> Sum<&'a ArmyPersonnel> for Maintenance {
72 fn sum<I>(iter: I) -> Self
73 where
74 I: Iterator<Item = &'a ArmyPersonnel>,
75 {
76 iter.flat_map(ArmyPersonnel::iter).sum()
77 }
78}
79
80impl<'a> Sum<&'a Army> for Maintenance {
81 fn sum<I>(iter: I) -> Self
82 where
83 I: Iterator<Item = &'a Army>,
84 {
85 iter.flat_map(Army::iter).sum()
86 }
87}
88
89const impl Add for Maintenance {
90 type Output = Self;
91
92 fn add(self, rhs: Self) -> Self {
93 Self(self.0 + rhs.0)
94 }
95}
96
97const impl Add<Food> for Maintenance {
98 type Output = Self;
99
100 fn add(self, rhs: Food) -> Self {
101 Self(self.0 + rhs)
102 }
103}
104
105const impl AddAssign for Maintenance {
106 fn add_assign(&mut self, rhs: Self) {
107 *self = Self(self.0 + rhs.0);
108 }
109}
110
111const impl AddAssign<Food> for Maintenance {
112 fn add_assign(&mut self, rhs: Food) {
113 *self = Self(self.0 + rhs);
114 }
115}
116
117const impl Sub for Maintenance {
118 type Output = Self;
119
120 fn sub(self, rhs: Self) -> Self {
121 Self(self.0 - rhs.0)
122 }
123}
124
125const impl Sub<Food> for Maintenance {
126 type Output = Self;
127
128 fn sub(self, rhs: Food) -> Self {
129 Self(self.0 - rhs)
130 }
131}
132
133const impl Sub<Maintenance> for Food {
134 type Output = Self;
135
136 fn sub(self, rhs: Maintenance) -> Self {
137 self - rhs.0
138 }
139}
140
141const impl Sub<Maintenance> for FoodDiff {
142 type Output = Self;
143
144 fn sub(self, rhs: Maintenance) -> Self {
145 self - rhs.0
146 }
147}
148
149const impl SubAssign for Maintenance {
150 fn sub_assign(&mut self, rhs: Self) {
151 *self = Self(self.0 - rhs.0);
152 }
153}
154
155const impl SubAssign<Food> for Maintenance {
156 fn sub_assign(&mut self, rhs: Food) {
157 *self = Self(self.0 - rhs);
158 }
159}
160
161const impl SubAssign<Maintenance> for Food {
162 fn sub_assign(&mut self, rhs: Maintenance) {
163 *self = *self - rhs.0;
164 }
165}
166
167const impl SubAssign<Maintenance> for FoodDiff {
168 fn sub_assign(&mut self, rhs: Maintenance) {
169 *self = *self - rhs.0;
170 }
171}
172
173const impl Mul<u32> for Maintenance {
174 type Output = Maintenance;
175
176 fn mul(self, rhs: u32) -> Self::Output {
177 Self(self.0 * rhs)
178 }
179}
180
181const impl Mul<NonZeroU32> for Maintenance {
182 type Output = Maintenance;
183
184 fn mul(self, rhs: NonZeroU32) -> Self::Output {
185 Self(self.0 * rhs.get())
186 }
187}
188
189const impl Div<UnitChunkSize> for Maintenance {
190 type Output = Maintenance;
191
192 fn div(self, rhs: UnitChunkSize) -> Self::Output {
193 let maintenance = f64::from(self);
194 let chunk_size = f64::from(rhs);
195 Self::from(maintenance / chunk_size)
196 }
197}
198
199const impl PartialEq<Food> for Maintenance {
200 fn eq(&self, other: &Food) -> bool {
201 self.0.eq(other)
202 }
203}
204
205const impl PartialEq<Maintenance> for Food {
206 fn eq(&self, other: &Maintenance) -> bool {
207 self.eq(&other.0)
208 }
209}
210
211const impl PartialOrd<Food> for Maintenance {
212 fn partial_cmp(&self, other: &Food) -> Option<Ordering> {
213 self.0.partial_cmp(other)
214 }
215}
216
217const impl PartialOrd<Maintenance> for Food {
218 fn partial_cmp(&self, other: &Maintenance) -> Option<Ordering> {
219 self.partial_cmp(&other.0)
220 }
221}
222
223#[derive(Copy, Debug, Display, Deserialize, Serialize, ConstDeref)]
225#[derive_const(Clone, PartialEq, PartialOrd)]
226#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
227pub struct MaintenanceRatio(f64);
228
229impl MaintenanceRatio {
230 #[inline]
231 pub const fn new(ratio: f64) -> Self {
232 debug_assert!(ratio.is_finite());
233 debug_assert!(!ratio.is_subnormal());
234 Self(ratio.clamp(0.0, 1.0))
235 }
236}
237
238const impl From<MaintenanceRatio> for f64 {
239 fn from(value: MaintenanceRatio) -> Self {
240 value.0
241 }
242}
243
244#[derive(Debug, Deserialize, Serialize)]
245#[derive_const(Clone)]
246#[serde(rename_all = "camelCase")]
247#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
248pub struct MaintenanceBalance {
249 pub maintenance: Maintenance,
250 pub production: Food,
251}
252
253impl MaintenanceBalance {
254 #[inline]
256 pub const fn is_sustainable(&self) -> bool {
257 self.production >= self.maintenance
258 }
259}
260
261const impl Add<Maintenance> for MaintenanceBalance {
262 type Output = Self;
263
264 fn add(self, rhs: Maintenance) -> Self::Output {
265 Self {
266 maintenance: self.maintenance + rhs,
267 production: self.production,
268 }
269 }
270}