tf2_enum/strange_part_set.rs
1//! Set for holding up to 3 strange parts.
2
3use std::fmt;
4use std::hash::{Hash, Hasher};
5use std::ops::{BitAnd, Sub};
6use crate::StrangePart;
7
8const STRANGE_PART_COUNT: usize = 3;
9
10/// Contains up to 3 strange parts. Although the underlying data structure is an array, this structure
11/// behaves like a set. Most methods mimic those of [`HashSet`](std::collections::HashSet).
12///
13/// This struct solves the following problems:
14/// - An item can only hold up to 3 strange parts.
15/// - An item cannot have duplicate strange parts.
16/// - Comparing strange parts for equality is order-agnostic.
17/// - Hashing is order-agnostic.
18/// - The type is `Copy`, allowing for cheap and easy duplication.
19///
20/// # Examples
21/// ```
22/// use tf2_enum::{StrangePartSet, StrangePart};
23///
24/// // Create a set for strange parts with two strange parts.
25/// let mut strange_parts = StrangePartSet::double(
26/// StrangePart::CriticalKills,
27/// StrangePart::DamageDealt,
28/// );
29///
30/// // Check that strange parts contains Damage Dealt.
31/// assert!(strange_parts.contains(&StrangePart::DamageDealt));
32/// assert_eq!(strange_parts.len(), 2);
33///
34/// // Add a strange part.
35/// strange_parts.insert(StrangePart::EngineersKilled);
36///
37/// assert_eq!(strange_parts.len(), 3);
38///
39/// // If a strange part is added when strange parts are full, the insert will fail.
40/// assert!(!strange_parts.insert(StrangePart::MedicsKilled));
41/// assert!(!strange_parts.contains(&StrangePart::MedicsKilled));
42///
43/// // Iterate over strange parts.
44/// for strange_part in strange_parts {
45/// println!("{strange_part}");
46/// }
47/// ```
48#[derive(Debug, Default, Clone, Copy, Eq)]
49pub struct StrangePartSet {
50 inner: [Option<StrangePart>; STRANGE_PART_COUNT],
51}
52
53impl StrangePartSet {
54 /// Creates a set for strange parts.
55 ///
56 /// # Examples
57 /// ```
58 /// use tf2_enum::StrangePartSet;
59 ///
60 /// let strange_parts = StrangePartSet::new();
61 /// ```
62 pub fn new() -> Self {
63 Self::default()
64 }
65
66 /// Creates a set for strange parts with one strange part.
67 ///
68 /// # Examples
69 /// ```
70 /// use tf2_enum::{StrangePartSet, StrangePart};
71 ///
72 /// let strange_parts = StrangePartSet::single(
73 /// StrangePart::DamageDealt,
74 /// );
75 ///
76 /// assert_eq!(strange_parts.len(), 1);
77 /// ```
78 pub fn single(strange_part: StrangePart) -> Self {
79 Self::from([
80 Some(strange_part),
81 None,
82 None,
83 ])
84 }
85
86 /// Creates a set for strange parts with two strange parts.
87 ///
88 /// If the same strange part is added multiple times, only one will be kept.
89 ///
90 /// # Examples
91 /// ```
92 /// use tf2_enum::{StrangePartSet, StrangePart};
93 ///
94 /// let strange_parts = StrangePartSet::double(
95 /// StrangePart::DamageDealt,
96 /// StrangePart::CriticalKills,
97 /// );
98 ///
99 /// assert_eq!(strange_parts.len(), 2);
100 /// ```
101 pub fn double(
102 strange_part1: StrangePart,
103 strange_part2: StrangePart,
104 ) -> Self {
105 Self::from([
106 Some(strange_part1),
107 Some(strange_part2),
108 None,
109 ])
110 }
111
112 /// Creates a set for strange parts with two strange parts.
113 ///
114 /// If the same strange part is added multiple times, only one will be kept.
115 ///
116 /// # Examples
117 /// ```
118 /// use tf2_enum::{StrangePartSet, StrangePart};
119 ///
120 /// let strange_parts = StrangePartSet::triple(
121 /// StrangePart::DamageDealt,
122 /// StrangePart::CriticalKills,
123 /// StrangePart::EngineersKilled,
124 /// );
125 ///
126 /// assert_eq!(strange_parts.len(), 3);
127 /// ```
128 pub fn triple(
129 strange_part1: StrangePart,
130 strange_part2: StrangePart,
131 strange_part3: StrangePart,
132 ) -> Self {
133 Self::from([
134 Some(strange_part1),
135 Some(strange_part2),
136 Some(strange_part3),
137 ])
138 }
139
140 /// Clears the set, removing all strange parts.
141 ///
142 /// # Examples
143 /// ```
144 /// use tf2_enum::{StrangePartSet, StrangePart};
145 ///
146 /// let mut strange_parts = StrangePartSet::double(
147 /// StrangePart::CriticalKills,
148 /// StrangePart::DamageDealt,
149 /// );
150 ///
151 /// strange_parts.clear();
152 ///
153 /// assert_eq!(strange_parts.len(), 0);
154 /// ```
155 pub fn clear(&mut self) {
156 self.inner = [None, None, None];
157 }
158
159 /// Adds a strange part to the first available slot. If no slots are available, the new strange
160 /// part will be ignored.
161 ///
162 /// Returns `false` if:
163 /// - The strange part is already in the set.
164 /// - The set is full.
165 ///
166 /// # Examples
167 /// ```
168 /// use tf2_enum::{StrangePartSet, StrangePart};
169 ///
170 /// let mut strange_parts = StrangePartSet::double(
171 /// StrangePart::CriticalKills,
172 /// StrangePart::DamageDealt,
173 /// );
174 ///
175 /// assert_eq!(strange_parts.len(), 2);
176 ///
177 /// strange_parts.insert(StrangePart::EngineersKilled);
178 ///
179 /// assert_eq!(strange_parts.len(), 3);
180 ///
181 /// // Strange parts are full.
182 /// assert!(!strange_parts.insert(StrangePart::MedicsKilled));
183 /// ```
184 pub fn insert(&mut self, strange_part: StrangePart) -> bool {
185 if self.contains(&strange_part) {
186 return false;
187 }
188
189 if let Some(slot) = self.inner.iter_mut().find(|slot| slot.is_none()) {
190 *slot = Some(strange_part);
191 return true;
192 }
193
194 // full set, insertion failed
195 false
196 }
197
198 /// Removes a strange part.
199 ///
200 /// # Examples
201 /// ```
202 /// use tf2_enum::{StrangePartSet, StrangePart};
203 ///
204 /// let mut strange_parts = StrangePartSet::single(StrangePart::CriticalKills);
205 ///
206 /// assert!(strange_parts.remove(&StrangePart::CriticalKills));
207 /// assert!(!strange_parts.contains(&StrangePart::CriticalKills));
208 /// ```
209 pub fn remove(&mut self, strange_part: &StrangePart) -> bool {
210 for s in self.inner.iter_mut() {
211 if *s == Some(*strange_part) {
212 *s = None;
213 return true;
214 }
215 }
216
217 false
218 }
219
220 /// Removes and returns the strange part in the set, if any, that is equal to the given one.
221 pub fn take(&mut self, strange_part: &StrangePart) -> Option<StrangePart> {
222 for s in self.inner.iter_mut() {
223 if *s == Some(*strange_part) {
224 *s = None;
225 return Some(*strange_part);
226 }
227 }
228
229 None
230 }
231
232 /// Returns `true` if the set contains no strange parts.
233 pub fn is_empty(&self) -> bool {
234 self.inner
235 .iter()
236 .all(|s| s.is_none())
237 }
238
239 /// Returns `true` if the set contains a strange part.
240 ///
241 /// # Examples
242 /// ```
243 /// use tf2_enum::{StrangePartSet, StrangePart};
244 ///
245 /// let strange_parts = StrangePartSet::from([
246 /// Some(StrangePart::CriticalKills),
247 /// Some(StrangePart::DamageDealt),
248 /// None,
249 /// ]);
250 ///
251 /// assert!(strange_parts.contains(&StrangePart::CriticalKills));
252 /// ```
253 pub fn contains(&self, strange_part: &StrangePart) -> bool {
254 self.inner.contains(&Some(*strange_part))
255 }
256
257 /// Returns the number of strange parts in the set.
258 ///
259 /// # Examples
260 /// ```
261 /// use tf2_enum::{StrangePartSet, StrangePart};
262 ///
263 /// let strange_parts = StrangePartSet::double(StrangePart::DamageDealt, StrangePart::CriticalKills);
264 ///
265 /// assert_eq!(strange_parts.len(), 2);
266 /// ```
267 pub fn len(&self) -> usize {
268 self.inner
269 .into_iter() // inner is Copy
270 .filter(Option::is_some)
271 .count()
272 }
273
274 /// Returns the strange parts that are in `self` but not in `other`.
275 ///
276 /// # Examples
277 /// ```
278 /// use tf2_enum::{StrangePartSet, StrangePart};
279 ///
280 /// let strange_parts1 = StrangePartSet::double(StrangePart::DamageDealt, StrangePart::CriticalKills);
281 /// let strange_parts2 = StrangePartSet::double(StrangePart::DamageDealt, StrangePart::EngineersKilled);
282 /// let difference = strange_parts1.difference(&strange_parts2);
283 ///
284 /// assert_eq!(difference, StrangePartSet::single(StrangePart::CriticalKills));
285 ///
286 /// let difference = strange_parts2.difference(&strange_parts1);
287 ///
288 /// assert_eq!(difference, StrangePartSet::single(StrangePart::EngineersKilled));
289 /// ```
290 pub fn difference(&self, other: &Self) -> Self {
291 let mut inner = [None, None, None];
292
293 for (i, s_option) in inner.iter_mut().enumerate() {
294 if let Some(s) = self.inner[i] {
295 if !other.contains(&s) {
296 *s_option = Some(s);
297 }
298 }
299 }
300
301 Self {
302 inner,
303 }
304 }
305
306 /// Returns the strange parts that are both in `self` and `other`.
307 ///
308 /// # Examples
309 /// ```
310 /// use tf2_enum::{StrangePartSet, StrangePart};
311 ///
312 /// let strange_parts1 = StrangePartSet::double(StrangePart::DamageDealt, StrangePart::CriticalKills);
313 /// let strange_parts2 = StrangePartSet::double(StrangePart::DamageDealt, StrangePart::EngineersKilled);
314 /// let intersection = strange_parts1.intersection(&strange_parts2);
315 ///
316 /// assert_eq!(intersection, StrangePartSet::single(StrangePart::DamageDealt));
317 /// ```
318 pub fn intersection(&self, other: &Self) -> Self {
319 let mut inner = [None, None, None];
320
321 for (i, s_option) in inner.iter_mut().enumerate() {
322 if let Some(s) = self.inner[i] {
323 if other.contains(&s) {
324 *s_option = Some(s);
325 }
326 }
327 }
328
329 Self {
330 inner,
331 }
332 }
333
334 /// Returns `true` if `self` has no strange parts in common with `other`. This is equivalent to
335 /// checking for an empty intersection.
336 ///
337 /// # Examples
338 /// ```
339 /// use tf2_enum::{StrangePartSet, StrangePart};
340 ///
341 /// let strange_parts1 = StrangePartSet::double(StrangePart::DamageDealt, StrangePart::CriticalKills);
342 /// let strange_parts2 = StrangePartSet::double(StrangePart::DamageDealt, StrangePart::EngineersKilled);
343 ///
344 /// assert!(!strange_parts1.is_disjoint(&strange_parts2));
345 /// ```
346 pub fn is_disjoint(&self, other: &Self) -> bool {
347 self.intersection(other).is_empty()
348 }
349
350 /// Returns true if the set is a subset of another, i.e., other contains at least all the values in self.
351 ///
352 /// # Examples
353 /// ```
354 /// use tf2_enum::{StrangePartSet, StrangePart};
355 ///
356 /// let sup = StrangePartSet::double(StrangePart::DamageDealt, StrangePart::CriticalKills);
357 /// let mut strange_parts = StrangePartSet::single(StrangePart::DamageDealt);
358 ///
359 /// assert!(strange_parts.is_subset(&sup));
360 ///
361 /// strange_parts.insert(StrangePart::EngineersKilled);
362 ///
363 /// assert!(!strange_parts.is_subset(&sup));
364 /// ```
365 pub fn is_subset(&self, other: &Self) -> bool {
366 if self.len() > other.len() {
367 return false;
368 }
369
370 self.iter().all(|strange_part| other.contains(strange_part))
371 }
372
373 /// Returns true if the set is a superset of another, i.e., self contains at least all the values in other.
374 ///
375 /// # Examples
376 /// ```
377 /// use tf2_enum::{StrangePartSet, StrangePart};
378 ///
379 /// let sub = StrangePartSet::double(StrangePart::DamageDealt, StrangePart::CriticalKills);
380 /// let mut strange_parts = StrangePartSet::new();
381 ///
382 /// assert!(!strange_parts.is_superset(&sub));
383 ///
384 /// strange_parts.insert(StrangePart::DamageDealt);
385 ///
386 /// assert!(!strange_parts.is_superset(&sub));
387 ///
388 /// strange_parts.insert(StrangePart::CriticalKills);
389 ///
390 /// assert!(strange_parts.is_superset(&sub));
391 /// ```
392 pub fn is_superset(&self, other: &Self) -> bool {
393 other.is_subset(self)
394 }
395
396 /// Returns an iterator over the strange parts in the set.
397 pub fn iter(&self) -> impl Iterator<Item = &StrangePart> {
398 self.inner.iter().filter_map(|opt| opt.as_ref())
399 }
400}
401
402impl From<[Option<StrangePart>; STRANGE_PART_COUNT]> for StrangePartSet {
403 fn from(inner: [Option<StrangePart>; STRANGE_PART_COUNT]) -> Self {
404 let mut inner = inner;
405
406 // remove duplicates
407 for i in 0..STRANGE_PART_COUNT {
408 if let Some(val_i) = inner[i] {
409 // check elements after i for duplicates
410 for j in (i + 1)..STRANGE_PART_COUNT {
411 if inner[j] == Some(val_i) {
412 // later occurrence exists, remove current
413 inner[i] = None;
414 break;
415 }
416 }
417 }
418 }
419
420 Self {
421 inner,
422 }
423 }
424}
425
426// Only Sub is implemented because Add wouldn't make much sense with strange parts being limited
427// to 3.
428impl Sub for StrangePartSet {
429 type Output = Self;
430
431 fn sub(self, other: Self) -> Self::Output {
432 self.difference(&other)
433 }
434}
435
436impl Sub for &StrangePartSet {
437 type Output = StrangePartSet;
438
439 fn sub(self, other: &StrangePartSet) -> Self::Output {
440 self.difference(other)
441 }
442}
443
444impl BitAnd for StrangePartSet {
445 type Output = Self;
446
447 fn bitand(self, other: Self) -> Self::Output {
448 self.intersection(&other)
449 }
450}
451
452impl BitAnd for &StrangePartSet {
453 type Output = StrangePartSet;
454
455 fn bitand(self, other: &StrangePartSet) -> Self::Output {
456 self.intersection(other)
457 }
458}
459
460impl PartialEq<Self> for StrangePartSet {
461 fn eq(&self, other: &Self) -> bool {
462 let mut a = self.inner;
463 let mut b = other.inner;
464
465 a.sort_unstable();
466 b.sort_unstable();
467
468 a == b
469 }
470}
471
472impl Hash for StrangePartSet {
473 fn hash<H: Hasher>(&self, state: &mut H) {
474 let mut values = self.inner;
475
476 values.sort_unstable();
477
478 for value in values {
479 value.hash(state);
480 }
481 }
482}
483
484impl FromIterator<StrangePart> for StrangePartSet {
485 fn from_iter<I: IntoIterator<Item = StrangePart>>(iter: I) -> Self {
486 let mut strange_parts = Self::new();
487
488 for strange_part in iter {
489 strange_parts.insert(strange_part);
490 }
491
492 strange_parts
493 }
494}
495
496impl IntoIterator for StrangePartSet {
497 type Item = StrangePart;
498 type IntoIter = StrangePartSetIterator;
499
500 fn into_iter(self) -> Self::IntoIter {
501 StrangePartSetIterator {
502 inner: self.inner.into_iter(),
503 }
504 }
505}
506
507impl IntoIterator for &StrangePartSet {
508 type Item = StrangePart;
509 type IntoIter = StrangePartSetIterator;
510
511 fn into_iter(self) -> Self::IntoIter {
512 StrangePartSetIterator {
513 inner: self.inner.into_iter(),
514 }
515 }
516}
517
518/// Iterator for strange parts.
519#[derive(Debug, Clone)]
520pub struct StrangePartSetIterator {
521 inner: std::array::IntoIter<Option<StrangePart>, STRANGE_PART_COUNT>,
522}
523
524impl Iterator for StrangePartSetIterator {
525 type Item = StrangePart;
526
527 fn next(&mut self) -> Option<Self::Item> {
528 let iter = self.inner.by_ref();
529
530 for opt in iter {
531 if opt.is_some() {
532 return opt;
533 }
534 }
535
536 None
537 }
538}
539
540impl fmt::Display for StrangePartSet {
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542 let mut iter = self.into_iter();
543
544 if let Some(first) = iter.next() {
545 write!(f, "{first}")?;
546
547 for s in iter {
548 write!(f, ", {s}")?;
549 }
550 }
551
552 Ok(())
553 }
554}
555
556#[cfg(test)]
557mod tests {
558 use super::*;
559 use crate::traits::Attributes;
560
561 #[test]
562 fn iterates_strange_parts() {
563 let strange_parts = StrangePartSet::from([
564 Some(StrangePart::TauntKills),
565 Some(StrangePart::KillsWhileExplosiveJumping),
566 Some(StrangePart::CriticalKills),
567 ]);
568 let mut iter = strange_parts.into_iter();
569
570 assert_eq!(iter.next(), Some(StrangePart::TauntKills));
571 assert_eq!(iter.next(), Some(StrangePart::KillsWhileExplosiveJumping));
572 assert_eq!(iter.next(), Some(StrangePart::CriticalKills));
573 assert_eq!(iter.next(), None);
574
575 let mut count = 0;
576
577 for _strange_part in &strange_parts {
578 count += 1;
579 }
580
581 assert_eq!(count, 3);
582 }
583
584 #[test]
585 fn mutates_strange_parts() {
586 let mut strange_parts = StrangePartSet::from([
587 Some(StrangePart::TauntKills),
588 Some(StrangePart::KillsWhileExplosiveJumping),
589 Some(StrangePart::CriticalKills),
590 ]);
591
592 assert_eq!(strange_parts.len(), 3);
593 assert!(strange_parts.contains(&StrangePart::CriticalKills));
594
595 strange_parts.remove(&StrangePart::CriticalKills);
596
597 assert!(!strange_parts.contains(&StrangePart::CriticalKills));
598 assert_eq!(strange_parts.len(), 2);
599
600 strange_parts.insert(StrangePart::DamageDealt);
601
602 assert!(strange_parts.contains(&StrangePart::DamageDealt));
603 assert_eq!(strange_parts.len(), 3);
604 }
605
606 #[test]
607 fn strange_parts_no_duplicates() {
608 assert_eq!(StrangePartSet::from([
609 Some(StrangePart::CriticalKills),
610 Some(StrangePart::CriticalKills),
611 Some(StrangePart::CriticalKills),
612 ]), StrangePartSet::from([
613 Some(StrangePart::CriticalKills),
614 None,
615 None,
616 ]));
617 }
618
619 #[test]
620 fn is_empty() {
621 assert!(StrangePartSet::from([
622 None,
623 None,
624 None,
625 ]).is_empty());
626 }
627
628 #[test]
629 fn iter_zip() {
630 let strange_parts = StrangePartSet::from([
631 Some(StrangePart::TauntKills),
632 Some(StrangePart::KillsWhileExplosiveJumping),
633 Some(StrangePart::CriticalKills),
634 ]);
635 let with_attribute_defindex = strange_parts.into_iter()
636 .zip(StrangePart::DEFINDEX.to_owned())
637 .collect::<Vec<_>>();
638
639 assert_eq!(with_attribute_defindex, vec![
640 (StrangePart::TauntKills, 380),
641 (StrangePart::KillsWhileExplosiveJumping, 382),
642 (StrangePart::CriticalKills, 384),
643 ]);
644 }
645
646 #[test]
647 fn stringify() {
648 let strange_parts = StrangePartSet::from([
649 Some(StrangePart::TauntKills),
650 Some(StrangePart::KillsWhileExplosiveJumping),
651 Some(StrangePart::CriticalKills),
652 ]);
653
654 assert_eq!(strange_parts.to_string(), "Taunt Kills, Kills While Explosive-Jumping, Critical Kills");
655 }
656
657 #[test]
658 fn bit_and() {
659 let set1 = StrangePartSet::from([
660 Some(StrangePart::TauntKills),
661 Some(StrangePart::KillsWhileExplosiveJumping),
662 Some(StrangePart::CriticalKills),
663 ]);
664 let set2 = StrangePartSet::from([
665 Some(StrangePart::TauntKills),
666 Some(StrangePart::DamageDealt),
667 None,
668 ]);
669 let intersection = set1 & set2;
670 assert_eq!(intersection, StrangePartSet::from([
671 Some(StrangePart::TauntKills),
672 None,
673 None,
674 ]));
675 }
676
677 #[test]
678 fn iterate_borrowed() {
679 let strange_parts = StrangePartSet::from([
680 Some(StrangePart::TauntKills),
681 Some(StrangePart::KillsWhileExplosiveJumping),
682 Some(StrangePart::CriticalKills),
683 ]);
684
685 for strange_part in &strange_parts {
686 assert!(strange_parts.contains(&strange_part));
687 }
688 }
689}