rosu_pp/any/difficulty/
gradual.rs

1use rosu_map::section::general::GameMode;
2
3use crate::{
4    any::DifficultyAttributes,
5    catch::{Catch, CatchGradualDifficulty},
6    mania::{Mania, ManiaGradualDifficulty},
7    model::mode::{ConvertError, IGameMode},
8    osu::{Osu, OsuGradualDifficulty},
9    taiko::{Taiko, TaikoGradualDifficulty},
10    Beatmap, Difficulty,
11};
12
13/// Gradually calculate the difficulty attributes on maps of any mode.
14///
15/// Note that this type implements [`Iterator`]. On every call of
16/// [`Iterator::next`], the next object will be processed and the
17/// [`DifficultyAttributes`] will be updated and returned.
18///
19/// If you want to calculate performance attributes, use [`GradualPerformance`] instead.
20///
21/// # Example
22///
23/// ```
24/// use rosu_pp::{Beatmap, GradualDifficulty, Difficulty};
25///
26/// let map = Beatmap::from_path("./resources/2785319.osu").unwrap();
27/// let difficulty = Difficulty::new().mods(64); // DT
28/// let mut iter = GradualDifficulty::new(difficulty, &map);
29///
30/// // the difficulty of the map after the first object
31/// let attrs1 = iter.next();
32/// // ... after the second object
33/// let attrs2 = iter.next();
34///
35/// // Remaining objects
36/// for difficulty in iter {
37///     // ...
38/// }
39/// ```
40///
41/// [`GradualPerformance`]: crate::GradualPerformance
42// 504 vs 184 bytes is an acceptable difference and the Osu variant (424 bytes)
43// is likely the most used one anyway.
44#[allow(clippy::large_enum_variant)]
45pub enum GradualDifficulty {
46    Osu(OsuGradualDifficulty),
47    Taiko(TaikoGradualDifficulty),
48    Catch(CatchGradualDifficulty),
49    Mania(ManiaGradualDifficulty),
50}
51
52impl GradualDifficulty {
53    /// Create a [`GradualDifficulty`] for a map of any mode.
54    #[allow(clippy::missing_panics_doc)]
55    pub fn new(difficulty: Difficulty, map: &Beatmap) -> Self {
56        Self::new_with_mode(difficulty, map, map.mode).expect("no conversion required")
57    }
58
59    /// Create a [`GradualDifficulty`] for a [`Beatmap`] on a specific [`GameMode`].
60    pub fn new_with_mode(
61        difficulty: Difficulty,
62        map: &Beatmap,
63        mode: GameMode,
64    ) -> Result<Self, ConvertError> {
65        match mode {
66            GameMode::Osu => Osu::gradual_difficulty(difficulty, map).map(Self::Osu),
67            GameMode::Taiko => Taiko::gradual_difficulty(difficulty, map).map(Self::Taiko),
68            GameMode::Catch => Catch::gradual_difficulty(difficulty, map).map(Self::Catch),
69            GameMode::Mania => Mania::gradual_difficulty(difficulty, map).map(Self::Mania),
70        }
71    }
72}
73
74impl Iterator for GradualDifficulty {
75    type Item = DifficultyAttributes;
76
77    fn next(&mut self) -> Option<Self::Item> {
78        match self {
79            GradualDifficulty::Osu(gradual) => gradual.next().map(DifficultyAttributes::Osu),
80            GradualDifficulty::Taiko(gradual) => gradual.next().map(DifficultyAttributes::Taiko),
81            GradualDifficulty::Catch(gradual) => gradual.next().map(DifficultyAttributes::Catch),
82            GradualDifficulty::Mania(gradual) => gradual.next().map(DifficultyAttributes::Mania),
83        }
84    }
85
86    fn size_hint(&self) -> (usize, Option<usize>) {
87        match self {
88            GradualDifficulty::Osu(gradual) => gradual.size_hint(),
89            GradualDifficulty::Taiko(gradual) => gradual.size_hint(),
90            GradualDifficulty::Catch(gradual) => gradual.size_hint(),
91            GradualDifficulty::Mania(gradual) => gradual.size_hint(),
92        }
93    }
94
95    fn nth(&mut self, n: usize) -> Option<Self::Item> {
96        match self {
97            GradualDifficulty::Osu(gradual) => gradual.nth(n).map(DifficultyAttributes::Osu),
98            GradualDifficulty::Taiko(gradual) => gradual.nth(n).map(DifficultyAttributes::Taiko),
99            GradualDifficulty::Catch(gradual) => gradual.nth(n).map(DifficultyAttributes::Catch),
100            GradualDifficulty::Mania(gradual) => gradual.nth(n).map(DifficultyAttributes::Mania),
101        }
102    }
103}
104
105impl ExactSizeIterator for GradualDifficulty {
106    fn len(&self) -> usize {
107        match self {
108            GradualDifficulty::Osu(gradual) => gradual.len(),
109            GradualDifficulty::Taiko(gradual) => gradual.len(),
110            GradualDifficulty::Catch(gradual) => gradual.len(),
111            GradualDifficulty::Mania(gradual) => gradual.len(),
112        }
113    }
114}