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}