1use std::{
2 collections::{
3 btree_map::{IntoValues, Values, ValuesMut},
4 btree_set::{IntoIter, Iter},
5 },
6 fmt::{Debug, Formatter, Result as FmtResult},
7 iter::{Copied, FusedIterator},
8};
9
10use crate::{legacy::GameModsLegacy, order::GameModOrder};
11
12use super::{GameMod, GameModIntermode};
13
14macro_rules! mods_iter {
15 (
16 $( #[$meta:meta] )*
17 $name:ident $( < $outer_lifetime:lifetime > )? :
18 $inner:ident < $( $inner_generic:tt ),+ > =>
19 $item:ty
20 ) => {
21 $( #[ $meta ] )*
22 pub struct $name $( < $outer_lifetime > )? {
23 inner: $inner < $( $inner_generic ),* >,
24 }
25
26 impl $( < $outer_lifetime > )? $name $( < $outer_lifetime > )? {
27 pub(super) const fn new(inner: $inner < $( $inner_generic ),* >) -> Self {
28 Self { inner }
29 }
30 }
31
32 impl $( < $outer_lifetime > )? Debug for $name $( < $outer_lifetime > )? {
33 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
34 Debug::fmt(&self.inner, f)
35 }
36 }
37
38 impl $( < $outer_lifetime > )? Iterator for $name $( < $outer_lifetime > )? {
39 type Item = $item;
40
41 fn next(&mut self) -> Option<Self::Item> {
42 self.inner.next()
43 }
44
45 fn size_hint(&self) -> (usize, Option<usize>) {
46 self.inner.size_hint()
47 }
48
49 fn last(mut self) -> Option<Self::Item> {
50 self.inner.next_back()
51 }
52 }
53
54 impl $( < $outer_lifetime > )? DoubleEndedIterator for $name $( < $outer_lifetime > )? {
55 fn next_back(&mut self) -> Option<Self::Item> {
56 self.inner.next_back()
57 }
58 }
59
60 impl $( < $outer_lifetime > )? ExactSizeIterator for $name $( < $outer_lifetime > )? {
61 fn len(&self) -> usize {
62 self.inner.len()
63 }
64 }
65
66 impl $( < $outer_lifetime > )? FusedIterator for $name $( < $outer_lifetime > )? {}
67 };
68}
69
70mods_iter! {
71 #[derive(Clone)]
72 #[doc = "Iterates over [`GameMod`] references"]
73 GameModsIter<'m>: Values<'m, GameModOrder, GameMod> => &'m GameMod
74}
75mods_iter! {
76 #[doc = "Iterates over mutable [`GameMod`] references"]
77 GameModsIterMut<'m>: ValuesMut<'m, GameModOrder, GameMod> => &'m mut GameMod
78}
79mods_iter! {
80 #[doc = "Iterates over [`GameMod`]"]
81 IntoGameModsIter: IntoValues<GameModOrder, GameMod> => GameMod
82}
83
84type GameModsIntermodeIterInner<'m> = Copied<Iter<'m, GameModIntermode>>;
85
86mods_iter! {
87 #[derive(Clone)]
88 #[doc = "Iterates over [`GameModIntermode`]"]
89 GameModsIntermodeIter<'m>: GameModsIntermodeIterInner<'m> => GameModIntermode
90}
91mods_iter! {
92 #[doc = "Iterates over [`GameModIntermode`]"]
93 IntoGameModsIntermodeIter: IntoIter<GameModIntermode> => GameModIntermode
94}
95
96pub struct GameModsLegacyIter {
98 mods: GameModsLegacy,
99 shift: usize,
100}
101
102impl GameModsLegacyIter {
103 pub const fn new(mods: GameModsLegacy) -> Self {
105 Self { mods, shift: 0 }
106 }
107}
108
109impl Iterator for GameModsLegacyIter {
110 type Item = GameModsLegacy;
111
112 fn next(&mut self) -> Option<Self::Item> {
113 if !self.mods.is_empty() {
114 loop {
115 if self.shift == 32 {
116 return None;
117 }
118
119 let mut bit = 1 << self.shift;
120 self.shift += 1;
121
122 if (GameModsLegacy::from_bits_retain(bit) == GameModsLegacy::SuddenDeath
123 && self.mods.contains(GameModsLegacy::Perfect))
124 || (GameModsLegacy::from_bits_retain(bit) == GameModsLegacy::DoubleTime
125 && self.mods.contains(GameModsLegacy::Nightcore))
126 {
127 continue;
128 }
129
130 if bit == (GameModsLegacy::Nightcore - GameModsLegacy::DoubleTime).bits() {
131 bit += GameModsLegacy::DoubleTime.bits();
132 } else if bit == (GameModsLegacy::Perfect - GameModsLegacy::SuddenDeath).bits() {
133 bit += GameModsLegacy::SuddenDeath.bits();
134 }
135
136 if self.mods.bits() & bit == bit {
137 let mods = GameModsLegacy::from_bits(bit);
138 self.mods.remove(mods);
139
140 return Some(mods);
141 }
142 }
143 } else if self.shift == 0 {
144 self.shift = 32;
145
146 Some(GameModsLegacy::NoMod)
147 } else {
148 None
149 }
150 }
151
152 fn size_hint(&self) -> (usize, Option<usize>) {
153 let len = self.len();
154
155 (len, Some(len))
156 }
157}
158
159impl ExactSizeIterator for GameModsLegacyIter {
162 fn len(&self) -> usize {
163 self.mods.len() + usize::from(self.mods.is_empty() && self.shift == 0)
164 }
165}
166
167impl FusedIterator for GameModsLegacyIter {}