nil_core/infrastructure/
storage.rs1use crate::continent::coord::Coord;
5use crate::error::{Error, Result};
6use crate::infrastructure::building::level::BuildingLevel;
7use crate::infrastructure::building::{Building, StorageId};
8use derive_more::{From, Into};
9use nil_num::growth::growth;
10use nil_util::ConstDeref;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13use std::iter::Sum;
14use std::ops::{Add, AddAssign, Sub, SubAssign};
15
16pub trait Storage: Building {
18 fn storage_id(&self) -> StorageId;
19 fn capacity(&self, stats: &StorageStatsTable) -> Result<StorageCapacity>;
21 fn min_capacity(&self) -> StorageCapacity;
23 fn max_capacity(&self) -> StorageCapacity;
25}
26
27#[derive(Clone, Debug, Deserialize, Serialize)]
28#[serde(rename_all = "camelCase")]
29#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
30pub struct StorageStats {
31 pub level: BuildingLevel,
32 pub capacity: StorageCapacity,
33}
34
35#[derive(Clone, Debug, Deserialize, Serialize)]
36#[serde(rename_all = "camelCase")]
37#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
38pub struct StorageStatsTable {
39 id: StorageId,
40 table: HashMap<BuildingLevel, StorageStats>,
41}
42
43impl StorageStatsTable {
44 pub(crate) fn new(storage: &dyn Storage) -> Self {
45 let max_level = storage.max_level();
46 let mut table = HashMap::with_capacity(max_level.into());
47
48 let mut capacity = f64::from(storage.min_capacity());
49 let capacity_growth = growth()
50 .floor(capacity)
51 .ceil(storage.max_capacity())
52 .max_level(max_level)
53 .call();
54
55 for level in 1..=u8::from(max_level) {
56 let level = BuildingLevel::new(level);
57 table.insert(
58 level,
59 StorageStats {
60 level,
61 capacity: StorageCapacity::from(capacity.ceil()),
62 },
63 );
64
65 debug_assert!(capacity.is_normal());
66
67 capacity += capacity * capacity_growth;
68 }
69
70 table.shrink_to_fit();
71
72 Self { id: storage.storage_id(), table }
73 }
74
75 #[inline]
76 pub fn id(&self) -> StorageId {
77 self.id
78 }
79
80 #[inline]
81 pub fn get(&self, level: BuildingLevel) -> Result<&StorageStats> {
82 self
83 .table
84 .get(&level)
85 .ok_or(Error::StorageStatsNotFoundForLevel(self.id, level))
86 }
87}
88
89#[derive(Clone, Copy, Debug, From, Into, Deserialize, Serialize, ConstDeref)]
91#[derive_const(Default, PartialEq, Eq, PartialOrd, Ord)]
92#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
93pub struct StorageCapacity(u32);
94
95impl StorageCapacity {
96 #[inline]
97 pub const fn new(value: u32) -> Self {
98 Self(value)
99 }
100}
101
102const impl From<f64> for StorageCapacity {
103 fn from(value: f64) -> Self {
104 Self::new(value as u32)
105 }
106}
107
108const impl From<StorageCapacity> for f64 {
109 fn from(value: StorageCapacity) -> Self {
110 f64::from(value.0)
111 }
112}
113
114const impl PartialEq<u32> for StorageCapacity {
115 fn eq(&self, other: &u32) -> bool {
116 self.0.eq(other)
117 }
118}
119
120const impl Add for StorageCapacity {
121 type Output = StorageCapacity;
122
123 fn add(self, rhs: Self) -> Self::Output {
124 Self(self.0.saturating_add(rhs.0))
125 }
126}
127
128const impl Add<u32> for StorageCapacity {
129 type Output = StorageCapacity;
130
131 fn add(self, rhs: u32) -> Self::Output {
132 Self(self.0.saturating_add(rhs))
133 }
134}
135
136const impl AddAssign for StorageCapacity {
137 fn add_assign(&mut self, rhs: Self) {
138 *self = *self + rhs;
139 }
140}
141
142const impl AddAssign<u32> for StorageCapacity {
143 fn add_assign(&mut self, rhs: u32) {
144 *self = *self + rhs;
145 }
146}
147
148const impl Sub for StorageCapacity {
149 type Output = StorageCapacity;
150
151 fn sub(self, rhs: Self) -> Self::Output {
152 Self(self.0.saturating_sub(rhs.0))
153 }
154}
155
156const impl Sub<u32> for StorageCapacity {
157 type Output = StorageCapacity;
158
159 fn sub(self, rhs: u32) -> Self::Output {
160 Self(self.0.saturating_sub(rhs))
161 }
162}
163
164const impl SubAssign for StorageCapacity {
165 fn sub_assign(&mut self, rhs: Self) {
166 *self = *self - rhs;
167 }
168}
169
170const impl SubAssign<u32> for StorageCapacity {
171 fn sub_assign(&mut self, rhs: u32) {
172 *self = *self - rhs;
173 }
174}
175
176impl Sum for StorageCapacity {
177 fn sum<I>(iter: I) -> Self
178 where
179 I: Iterator<Item = Self>,
180 {
181 iter.fold(Self::default(), |acc, capacity| acc + capacity)
182 }
183}
184
185#[derive(Copy, Debug, Deserialize, Serialize)]
186#[derive_const(Clone, Default, PartialEq, Eq)]
187#[serde(rename_all = "camelCase")]
188#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
189pub struct OverallStorageCapacity {
190 pub silo: StorageCapacity,
191 pub warehouse: StorageCapacity,
192}
193
194impl OverallStorageCapacity {
195 pub const fn mean(&self) -> f64 {
196 let Self { silo, warehouse } = *self;
197 let total = f64::from(silo) + f64::from(warehouse);
198 total / 2.0
199 }
200}
201
202const impl Add for OverallStorageCapacity {
203 type Output = OverallStorageCapacity;
204
205 fn add(mut self, rhs: Self) -> Self::Output {
206 self += rhs;
207 self
208 }
209}
210
211const impl AddAssign for OverallStorageCapacity {
212 fn add_assign(&mut self, rhs: Self) {
213 self.silo += rhs.silo;
214 self.warehouse += rhs.warehouse;
215 }
216}
217
218#[derive(Copy, Debug, From, Into, ConstDeref)]
219#[derive_const(Clone, Default, PartialEq, PartialOrd)]
220pub struct StorageCapacityWeight(f64);
221
222#[derive(Clone, Debug)]
223pub struct OverallStorageCapacityWeight {
224 pub coord: Coord,
225 pub silo: StorageCapacityWeight,
226 pub warehouse: StorageCapacityWeight,
227}
228
229impl OverallStorageCapacityWeight {
230 pub const fn new(coord: Coord) -> Self {
231 Self {
232 coord,
233 silo: StorageCapacityWeight::default(),
234 warehouse: StorageCapacityWeight::default(),
235 }
236 }
237}