rosu_pp/model/
mode.rs

1use std::{
2    error::Error,
3    fmt::{Display, Formatter, Result as FmtResult},
4};
5
6pub use rosu_map::section::general::GameMode;
7
8use crate::Difficulty;
9
10use super::beatmap::Beatmap;
11
12/// A way to specify a gamemode at compile-time.
13///
14/// Notably, this is implemented for the marker types [`Osu`], [`Taiko`],
15/// [`Catch`], and [`Mania`].
16///
17/// [`Osu`]: crate::osu::Osu
18/// [`Taiko`]: crate::taiko::Taiko
19/// [`Catch`]: crate::catch::Catch
20/// [`Mania`]: crate::mania::Mania
21pub trait IGameMode: Sized {
22    /// The resulting type of a difficulty calculation.
23    type DifficultyAttributes;
24
25    /// The resulting type of a strain calculation.
26    type Strains;
27
28    /// The type of a performance calculator.
29    type Performance<'map>;
30
31    /// The type of a gradual difficulty calculator.
32    type GradualDifficulty;
33
34    /// The type of a gradual performance calculator.
35    type GradualPerformance;
36
37    /// Perform a difficulty calculation for a [`Beatmap`] and process the
38    /// final skill values.
39    fn difficulty(
40        difficulty: &Difficulty,
41        map: &Beatmap,
42    ) -> Result<Self::DifficultyAttributes, ConvertError>;
43
44    /// Perform a difficulty calculation for a [`Beatmap`] without processing
45    /// the final skill values.
46    fn strains(difficulty: &Difficulty, map: &Beatmap) -> Result<Self::Strains, ConvertError>;
47
48    /// Create a performance calculator for a [`Beatmap`].
49    fn performance(map: &Beatmap) -> Self::Performance<'_>;
50
51    /// Create a gradual difficulty calculator for a [`Beatmap`].
52    fn gradual_difficulty(
53        difficulty: Difficulty,
54        map: &Beatmap,
55    ) -> Result<Self::GradualDifficulty, ConvertError>;
56
57    /// Create a gradual performance calculator for a [`Beatmap`].
58    fn gradual_performance(
59        difficulty: Difficulty,
60        map: &Beatmap,
61    ) -> Result<Self::GradualPerformance, ConvertError>;
62}
63
64/// Error type when failing to convert a [`Beatmap`] from one [`GameMode`] to
65/// another.
66#[derive(Copy, Clone, Debug)]
67pub enum ConvertError {
68    /// Cannot convert an already converted map
69    AlreadyConverted,
70    /// Cannot convert from [`GameMode`] `from` to `to`
71    Convert { from: GameMode, to: GameMode },
72}
73
74impl Error for ConvertError {
75    fn source(&self) -> Option<&(dyn Error + 'static)> {
76        None
77    }
78}
79
80impl Display for ConvertError {
81    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
82        match self {
83            ConvertError::AlreadyConverted => {
84                f.write_str("Cannot convert an already converted map")
85            }
86            ConvertError::Convert { from, to } => {
87                write!(f, "Cannot convert from {from:?} to {to:?}")
88            }
89        }
90    }
91}