deepwoken_reqparse/model/
req.rs1use core::fmt;
2use std::{borrow::Borrow, collections::{BTreeSet, HashSet}, str::FromStr};
3
4use serde::{Deserialize, Deserializer, Serialize, de};
5
6use crate::{Stat, util::statmap::StatMap};
7
8#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub enum Reducability {
10 Reducible,
11 Strict,
12}
13
14impl fmt::Display for Reducability {
15 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16 match self {
17 Reducability::Reducible => write!(f, "r"),
18 Reducability::Strict => write!(f, "s"),
19 }
20 }
21}
22
23pub type StatSet = BTreeSet<Stat>;
24
25#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
26pub struct Atom {
27 pub(crate) reducability: Reducability,
28 pub(crate) value: i64,
29 pub(crate) stats: StatSet,
31}
32
33impl Atom {
34 pub fn new(r: Reducability) -> Self {
35 Self {
36 reducability: r,
37 value: 0,
38 stats: BTreeSet::new(),
39 }
40 }
41
42 pub fn strict() -> Self {
43 Self {
44 reducability: Reducability::Strict,
45 value: 0,
46 stats: BTreeSet::new(),
47 }
48 }
49
50 pub fn reducible() -> Self {
51 Self {
52 reducability: Reducability::Reducible,
53 value: 0,
54 stats: BTreeSet::new(),
55 }
56 }
57
58 pub fn value(mut self, v: i64) -> Self {
59 self.value = v;
60 self
61 }
62
63 pub fn reducability(mut self, r: Reducability) -> Self {
64 self.reducability = r;
65 self
66 }
67
68 pub fn stat(mut self, stat: Stat) -> Self {
70 self.stats.insert(stat);
71 self
72 }
73
74 pub fn add_stat(&mut self, stat: Stat) {
75 self.stats.insert(stat);
76 }
77
78 pub fn satisfied_by(&self, stats: &StatMap) -> bool {
79 let sum: i64 = self
80 .stats
81 .iter()
82 .map(|s| {
83 if s == &Stat::Total {
84 stats.cost()
85 } else {
86 stats.get(s)
87 }
88 })
89 .sum();
90
91 sum >= self.value
92 }
93
94 pub fn is_empty(&self) -> bool {
96 self.stats.is_empty() && self.value == 0
97 }
98}
99
100impl fmt::Display for Atom {
101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102 if self.stats.len() == 1 {
103 write!(
104 f, "{}{} {}",
105 self.value,
106 self.reducability,
107 self.stats.first().unwrap().short_name()
108 )
109 } else {
110 let sum_expr = self
112 .stats
113 .iter()
114 .map(|s| s.short_name().to_string())
115 .collect::<Vec<String>>()
116 .join(" + ");
117
118 write!(f, "{} = {}{}", sum_expr, self.value, self.reducability)
119 }
120 }
121}
122
123#[derive(Clone, Debug, PartialEq, Eq, Hash)]
124pub enum ClauseType {
125 And,
126 Or,
127}
128
129#[derive(Clone, Debug, Hash, PartialEq, Eq)]
130pub struct Clause {
131 pub(crate) clause_type: ClauseType,
132 pub(crate) atoms: BTreeSet<Atom>,
133}
134
135impl Clause {
136 pub fn new(clause_type: ClauseType) -> Self {
137 Self {
138 clause_type,
139 atoms: BTreeSet::new(),
140 }
141 }
142
143 pub fn and() -> Self {
144 Self {
145 clause_type: ClauseType::And,
146 atoms: BTreeSet::new(),
147 }
148 }
149
150 pub fn or() -> Self {
151 Self {
152 clause_type: ClauseType::Or,
153 atoms: BTreeSet::new(),
154 }
155 }
156
157 pub fn clause_type(mut self, ct: ClauseType) -> Self {
158 self.clause_type = ct;
159 self
160 }
161
162 pub fn atoms(&self) -> &BTreeSet<Atom> {
163 &self.atoms
164 }
165
166 pub fn atoms_mut(&mut self) -> &mut BTreeSet<Atom> {
167 &mut self.atoms
168 }
169
170 pub fn insert(mut self, stats: StatSet, mut atom: Atom) -> Self {
171 atom.stats = stats;
172 self.atoms.insert(atom);
173 self
174 }
175
176 pub fn atom(mut self, atom: Atom) -> Self {
177 self.atoms.insert(atom);
178 self
179 }
180
181 pub fn add_atom(&mut self, atom: Atom) {
182 self.atoms.insert(atom);
183 }
184
185 pub fn satisfied_by(&self, stats: &StatMap) -> bool {
186 match self.clause_type {
187 ClauseType::And => self.atoms.iter().all(|atom| atom.satisfied_by(stats)),
188 ClauseType::Or => self.atoms.iter().any(|atom| atom.satisfied_by(stats)),
189 }
190 }
191
192 pub fn is_empty(&self) -> bool {
193 !self.atoms().iter().any(|a| !a.is_empty())
194 }
195}
196
197impl fmt::Display for Clause {
198 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199 let joiner = match self.clause_type {
200 ClauseType::And => ", ",
201 ClauseType::Or => " OR ",
202 };
203
204 let atom_strs: Vec<String> = self
205 .atoms
206 .iter()
207 .filter(|a| !a.is_empty())
208 .map(|atom| format!("{}", atom))
209 .collect();
210
211 write!(f, "{}", atom_strs.join(joiner))
212 }
213}
214
215#[derive(Clone, Debug, Hash)]
216pub struct Requirement {
217 pub(crate) name: Option<String>,
219 pub(crate) prereqs: Vec<String>,
221
222 pub(crate) clauses: Vec<Clause>,
223}
224
225impl PartialEq for Requirement {
226 fn eq(&self, other: &Self) -> bool {
227 if self.clauses.len() != other.clauses.len() {
228 return false;
229 }
230
231 self.clauses.iter().all(|c| other.clauses.contains(c))
233 && other.clauses.iter().all(|c| self.clauses.contains(c))
234 && self.name_or_default() == other.name_or_default()
235 }
237}
238
239impl Eq for Requirement {}
240
241impl Requirement {
242 pub fn new() -> Self {
243 Self {
244 name: None,
245 prereqs: Vec::new(),
246 clauses: Vec::new(),
247 }
248 }
249
250 pub fn add_clause(&mut self, clause: Clause) -> &mut Self {
251 self.clauses.push(clause);
252 self
253 }
254
255 pub fn add_prereq(&mut self, prereq: &str) -> &mut Self {
256 self.prereqs.push(prereq.to_string());
257 self
258 }
259
260 pub fn name(&mut self, name: &str) -> &mut Self {
261 self.name = Some(name.to_string());
262 self
263 }
264
265 pub fn name_or_default(&self) -> String {
266 match &self.name {
267 Some(n) => n.clone(),
268 None => self.to_string(),
269 }
270 }
271
272 pub fn iter(&self) -> impl Iterator<Item = &Clause> {
273 self.clauses.iter()
274 }
275
276 pub fn and_iter(&self) -> impl Iterator<Item = &Clause> {
277 self.clauses
278 .iter()
279 .filter(|c| c.clause_type == ClauseType::And)
280 }
281
282 pub fn or_iter(&self) -> impl Iterator<Item = &Clause> {
283 self.clauses
284 .iter()
285 .filter(|c| c.clause_type == ClauseType::Or)
286 }
287
288 pub fn atoms(&self) -> impl Iterator<Item = &Atom> {
289 self.clauses.iter().flat_map(|clause| clause.atoms.iter())
290 }
291
292 pub fn add_to_all(&mut self, val: i64) -> &mut Self {
293 for clause in &mut self.clauses {
295 clause.atoms = clause
296 .atoms
297 .iter()
298 .map(|atom| {
299 let mut new_atom = atom.clone();
300 new_atom.value += val;
301 new_atom.value = new_atom.value.clamp(0, 100);
302 new_atom
303 })
304 .collect();
305 }
306 self
307 }
308
309 pub fn strict_atoms(&self) -> impl Iterator<Item = &Atom> {
310 self.clauses.iter().flat_map(|clause| {
311 clause
312 .atoms
313 .iter()
314 .filter(|atom| atom.reducability == Reducability::Strict)
315 })
316 }
317
318 pub fn used_stats(&self) -> HashSet<Stat> {
320 self.atoms().fold(HashSet::new(), |mut acc, atom| {
321 for stat in &atom.stats {
322 if stat == &Stat::Total {
323 continue;
324 }
325
326 acc.insert(stat.clone());
327 }
328 acc
329 })
330 }
331
332 pub fn satisfied_by(&self, stats: &StatMap) -> bool {
333 self.clauses.iter().all(|clause| clause.satisfied_by(stats))
334 }
335
336 pub fn is_empty(&self) -> bool {
338 !self.clauses.iter().any(|c| !c.is_empty())
339 }
340}
341
342impl From<Clause> for Requirement {
343 fn from(clause: Clause) -> Self {
344 Self {
345 name: None,
346 prereqs: Vec::new(),
347 clauses: vec![clause],
348 }
349 }
350}
351
352impl fmt::Display for Requirement {
353 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
354 if !self.prereqs.is_empty() {
355 write!(f, "{} => ", self.prereqs.join(", "))?;
356 }
357 if let Some(name) = &self.name {
358 write!(f, "{} := ", name)?;
359 }
360 if self.is_empty() {
361 write!(f, "()")
362 } else {
363 let clause_strs: Vec<String> = self
364 .clauses
365 .iter()
366 .filter(|clause| !clause.is_empty())
367 .map(|clause| clause.to_string())
368 .collect();
369
370 write!(f, "{}", clause_strs.join(", "))
371 }
372 }
373}
374
375impl FromStr for Requirement {
376 type Err = String;
377
378 fn from_str(s: &str) -> Result<Self, Self::Err> {
379 crate::parse::req::parse_req(s).map_err(|e| format!("Failed to parse requirement: {}", e))
380 }
381}
382
383impl<'de> Deserialize<'de> for Requirement {
384 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
385 where
386 D: Deserializer<'de>,
387 {
388 let s = String::deserialize(deserializer)?;
389 s.parse().map_err(de::Error::custom)
390 }
391}
392
393impl Serialize for Requirement {
394 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
395 where
396 S: serde::Serializer,
397 {
398 serializer.serialize_str(&self.to_string())
399 }
400}
401
402#[derive(Clone, Copy, Debug)]
403pub enum Timing {
404 Free,
405 Post,
406}