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
35impl const From<u32> for Maintenance {
36 fn from(value: u32) -> Self {
37 Self::new(value)
38 }
39}
40
41impl const From<Maintenance> for u32 {
42 fn from(value: Maintenance) -> Self {
43 u32::from(value.0)
44 }
45}
46
47impl const 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
54impl const 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(), |mut acc, squad| {
66 acc += squad.maintenance();
67 acc
68 })
69 }
70}
71
72impl<'a> Sum<&'a ArmyPersonnel> for Maintenance {
73 fn sum<I>(iter: I) -> Self
74 where
75 I: Iterator<Item = &'a ArmyPersonnel>,
76 {
77 iter.flat_map(ArmyPersonnel::iter).sum()
78 }
79}
80
81impl<'a> Sum<&'a Army> for Maintenance {
82 fn sum<I>(iter: I) -> Self
83 where
84 I: Iterator<Item = &'a Army>,
85 {
86 iter.flat_map(Army::iter).sum()
87 }
88}
89
90impl const Add for Maintenance {
91 type Output = Self;
92
93 fn add(self, rhs: Self) -> Self {
94 Self(self.0 + rhs.0)
95 }
96}
97
98impl const Add<Food> for Maintenance {
99 type Output = Self;
100
101 fn add(self, rhs: Food) -> Self {
102 Self(self.0 + rhs)
103 }
104}
105
106impl const AddAssign for Maintenance {
107 fn add_assign(&mut self, rhs: Self) {
108 *self = Self(self.0 + rhs.0);
109 }
110}
111
112impl const AddAssign<Food> for Maintenance {
113 fn add_assign(&mut self, rhs: Food) {
114 *self = Self(self.0 + rhs);
115 }
116}
117
118impl const Sub for Maintenance {
119 type Output = Self;
120
121 fn sub(self, rhs: Self) -> Self {
122 Self(self.0 - rhs.0)
123 }
124}
125
126impl const Sub<Food> for Maintenance {
127 type Output = Self;
128
129 fn sub(self, rhs: Food) -> Self {
130 Self(self.0 - rhs)
131 }
132}
133
134impl const Sub<Maintenance> for Food {
135 type Output = Self;
136
137 fn sub(self, rhs: Maintenance) -> Self {
138 self - rhs.0
139 }
140}
141
142impl const Sub<Maintenance> for FoodDiff {
143 type Output = Self;
144
145 fn sub(self, rhs: Maintenance) -> Self {
146 self - rhs.0
147 }
148}
149
150impl const SubAssign for Maintenance {
151 fn sub_assign(&mut self, rhs: Self) {
152 *self = Self(self.0 - rhs.0);
153 }
154}
155
156impl const SubAssign<Food> for Maintenance {
157 fn sub_assign(&mut self, rhs: Food) {
158 *self = Self(self.0 - rhs);
159 }
160}
161
162impl const SubAssign<Maintenance> for Food {
163 fn sub_assign(&mut self, rhs: Maintenance) {
164 *self = *self - rhs.0;
165 }
166}
167
168impl const SubAssign<Maintenance> for FoodDiff {
169 fn sub_assign(&mut self, rhs: Maintenance) {
170 *self = *self - rhs.0;
171 }
172}
173
174impl const Mul<u32> for Maintenance {
175 type Output = Maintenance;
176
177 fn mul(self, rhs: u32) -> Self::Output {
178 Self(self.0 * rhs)
179 }
180}
181
182impl const Mul<NonZeroU32> for Maintenance {
183 type Output = Maintenance;
184
185 fn mul(self, rhs: NonZeroU32) -> Self::Output {
186 Self(self.0 * rhs.get())
187 }
188}
189
190impl const Div<UnitChunkSize> for Maintenance {
191 type Output = Maintenance;
192
193 fn div(self, rhs: UnitChunkSize) -> Self::Output {
194 let maintenance = f64::from(self);
195 let chunk_size = f64::from(rhs);
196 Self::from(maintenance / chunk_size)
197 }
198}
199
200impl const PartialEq<Food> for Maintenance {
201 fn eq(&self, other: &Food) -> bool {
202 self.0.eq(other)
203 }
204}
205
206impl const PartialEq<Maintenance> for Food {
207 fn eq(&self, other: &Maintenance) -> bool {
208 self.eq(&other.0)
209 }
210}
211
212impl const PartialOrd<Food> for Maintenance {
213 fn partial_cmp(&self, other: &Food) -> Option<Ordering> {
214 self.0.partial_cmp(other)
215 }
216}
217
218impl const PartialOrd<Maintenance> for Food {
219 fn partial_cmp(&self, other: &Maintenance) -> Option<Ordering> {
220 self.partial_cmp(&other.0)
221 }
222}
223
224#[derive(Clone, Copy, Debug, Deserialize, Serialize, ConstDeref)]
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
238impl const 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
261impl const 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}