nil_core/infrastructure/
queue.rs1use crate::resources::workforce::Workforce;
5use std::collections::VecDeque;
6
7pub trait InfrastructureQueue<T>
8where
9 T: InfrastructureQueueOrder,
10{
11 fn queue(&self) -> &VecDeque<T>;
12 fn queue_mut(&mut self) -> &mut VecDeque<T>;
13
14 fn process(&mut self, mut workforce: Workforce) -> Vec<T> {
16 let mut orders = Vec::new();
17 loop {
18 if workforce == 0 {
19 break;
20 }
21
22 match self
23 .queue_mut()
24 .pop_front_if(|order| order.consume(&mut workforce))
25 {
26 Some(order) => orders.push(order),
27 None => break,
28 }
29 }
30
31 if !orders.is_empty() {
32 self.queue_mut().shrink_to_fit();
33 }
34
35 orders
36 }
37
38 fn iter<'a>(&'a self) -> impl Iterator<Item = &'a T>
39 where
40 T: 'a,
41 {
42 self.queue().iter()
43 }
44
45 fn len(&self) -> usize {
46 self.queue().len()
47 }
48
49 fn is_empty(&self) -> bool {
50 self.queue().is_empty()
51 }
52
53 fn sum_pending_workforce(&self) -> Workforce {
54 self
55 .iter()
56 .filter_map(InfrastructureQueueOrder::pending_workforce)
57 .map(u32::from)
58 .sum::<u32>()
59 .into()
60 }
61}
62
63pub trait InfrastructureQueueOrder {
64 fn is_done(&self) -> bool;
65 fn set_done(&mut self);
66
67 fn pending_workforce(&self) -> Option<Workforce>;
68 fn pending_workforce_mut(&mut self) -> Option<&mut Workforce>;
69
70 fn consume(&mut self, workforce: &mut Workforce) -> bool {
71 if let Some(pending) = self.pending_workforce_mut() {
72 if *pending > 0 {
73 let previous = *pending;
74 *pending -= *workforce;
75
76 *workforce -= previous - *pending;
78 }
79
80 if *pending == 0 {
81 self.set_done();
82 }
83 }
84
85 self.is_done()
86 }
87}
88
89#[doc(hidden)]
90#[macro_export]
91macro_rules! decl_recruit_queue {
92 ($building:ident) => {
93 paste::paste! {
94 #[derive(Clone, Debug, Default, Deserialize, Serialize)]
95 #[serde(rename_all = "camelCase")]
96 pub struct [<$building RecruitQueue>] {
97 orders: VecDeque<[<$building RecruitOrder>]>,
98 }
99
100 impl [<$building RecruitQueue>] {
101 pub(crate) fn recruit(
102 &mut self,
103 request: &[<$building RecruitOrderRequest>],
104 current_resources: Option<&Resources>,
105 ) -> Result<&[<$building RecruitOrder>]> {
106 let unit = UnitBox::from(request.unit);
107 let chunk = unit.as_dyn().chunk();
108 let size = SquadSize::new(chunk.size() * request.chunks);
109 let resources = &chunk.resources() * request.chunks;
110 let workforce = chunk.workforce() * request.chunks;
111
112 if let Some(current_resources) = current_resources
113 && current_resources
114 .checked_sub(&resources)
115 .is_none()
116 {
117 return Err(Error::InsufficientResources);
118 }
119
120 self.orders.push_back([<$building RecruitOrder>] {
121 id: [<$building RecruitOrderId>]::new(),
122 squad: Squad::new(unit.id(), size),
123 resources,
124 workforce,
125 state: [<$building RecruitOrderState>]::new(workforce),
126 });
127
128 let len = self.orders.len();
129 Ok(unsafe {
130 self
131 .orders
132 .get(len.unchecked_sub(1))
133 .unwrap_unchecked()
134 })
135 }
136
137 #[must_use]
139 pub(crate) fn cancel(&mut self, id: [<$building RecruitOrderId>]) -> Option<[<$building RecruitOrder>]> {
140 let position = self
141 .orders
142 .iter()
143 .position(|order| order.id == id)?;
144
145 self.orders.remove(position)
146 }
147 }
148
149 impl InfrastructureQueue<[<$building RecruitOrder>]> for [<$building RecruitQueue>] {
150 fn queue(&self) -> &VecDeque<[<$building RecruitOrder>]> {
151 &self.orders
152 }
153
154 fn queue_mut(&mut self) -> &mut VecDeque<[<$building RecruitOrder>]> {
155 &mut self.orders
156 }
157 }
158
159 #[must_use]
160 #[derive(Clone, Debug, Deserialize, Serialize)]
161 #[serde(rename_all = "camelCase")]
162 pub struct [<$building RecruitOrder>] {
163 id: [<$building RecruitOrderId>],
164 squad: Squad,
165 resources: Resources,
166 workforce: Workforce,
167 state: [<$building RecruitOrderState>],
168 }
169
170 impl [<$building RecruitOrder>] {
171 #[inline]
172 pub fn id(&self) -> [<$building RecruitOrderId>] {
173 self.id
174 }
175
176 #[inline]
177 pub fn squad(&self) -> &Squad {
178 &self.squad
179 }
180
181 #[inline]
182 pub fn resources(&self) -> &Resources {
183 &self.resources
184 }
185 }
186
187 impl From<[<$building RecruitOrder>]> for Squad {
188 fn from(order: [<$building RecruitOrder>]) -> Self {
189 order.squad
190 }
191 }
192
193 impl InfrastructureQueueOrder for [<$building RecruitOrder>] {
194 fn is_done(&self) -> bool {
195 self.state.is_done()
196 }
197
198 fn set_done(&mut self) {
199 self.state = [<$building RecruitOrderState>]::Done;
200 }
201
202 fn pending_workforce(&self) -> Option<Workforce> {
203 self.state.pending_workforce()
204 }
205
206 fn pending_workforce_mut(&mut self) -> Option<&mut Workforce> {
207 self.state.pending_workforce_mut()
208 }
209 }
210
211 #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
212 pub struct [<$building RecruitOrderId>](Uuid);
213
214 impl [<$building RecruitOrderId>] {
215 #[must_use]
216 pub fn new() -> Self {
217 Self(Uuid::new_v4())
218 }
219 }
220
221 impl Default for [<$building RecruitOrderId>] {
222 fn default() -> Self {
223 Self::new()
224 }
225 }
226
227 #[derive(Clone, Debug, EnumIs, Deserialize, Serialize)]
228 #[serde(tag = "kind", rename_all = "kebab-case")]
229 pub enum [<$building RecruitOrderState>] {
230 Pending { workforce: Workforce },
231 Done,
232 }
233
234 impl [<$building RecruitOrderState>] {
235 fn pending_workforce(&self) -> Option<Workforce> {
236 if let Self::Pending { workforce } = self { Some(*workforce) } else { None }
237 }
238
239 fn pending_workforce_mut(&mut self) -> Option<&mut Workforce> {
240 if let Self::Pending { workforce } = self { Some(workforce) } else { None }
241 }
242 }
243
244 impl [<$building RecruitOrderState>] {
245 fn new(workforce: Workforce) -> Self {
246 Self::Pending { workforce }
247 }
248 }
249
250 #[derive(Clone, Debug, Deserialize, Serialize)]
251 #[serde(rename_all = "camelCase")]
252 pub struct [<$building RecruitOrderRequest>] {
253 pub coord: Coord,
254 pub unit: [<$building UnitId>],
255 pub chunks: NonZeroU32,
256 }
257 }
258 };
259}