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, any::CalculateError};
9
10use super::beatmap::Beatmap;
11
12pub trait IGameMode: Sized {
22 type DifficultyAttributes;
24
25 type Strains;
27
28 type Performance<'map>;
30
31 type HitResults;
33
34 type GradualDifficulty;
36
37 type GradualPerformance;
39
40 fn difficulty(
43 difficulty: &Difficulty,
44 map: &Beatmap,
45 ) -> Result<Self::DifficultyAttributes, ConvertError>;
46
47 fn checked_difficulty(
50 difficulty: &Difficulty,
51 map: &Beatmap,
52 ) -> Result<Self::DifficultyAttributes, CalculateError>;
53
54 fn strains(difficulty: &Difficulty, map: &Beatmap) -> Result<Self::Strains, ConvertError>;
57
58 fn performance(map: &Beatmap) -> Self::Performance<'_>;
60
61 fn gradual_difficulty(
63 difficulty: Difficulty,
64 map: &Beatmap,
65 ) -> Result<Self::GradualDifficulty, ConvertError>;
66
67 fn gradual_performance(
69 difficulty: Difficulty,
70 map: &Beatmap,
71 ) -> Result<Self::GradualPerformance, ConvertError>;
72}
73
74#[derive(Copy, Clone, Debug)]
77pub enum ConvertError {
78 AlreadyConverted,
80 Convert { from: GameMode, to: GameMode },
82}
83
84impl Error for ConvertError {
85 fn source(&self) -> Option<&(dyn Error + 'static)> {
86 None
87 }
88}
89
90impl Display for ConvertError {
91 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
92 match self {
93 ConvertError::AlreadyConverted => {
94 f.write_str("Cannot convert an already converted map")
95 }
96 ConvertError::Convert { from, to } => {
97 write!(f, "Cannot convert from {from:?} to {to:?}")
98 }
99 }
100 }
101}