From b044c9e67d5e3903a06215d620b79dd42831004b Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Sat, 29 Jun 2024 03:21:16 +0200 Subject: [PATCH 1/3] use rosu-mods & restructure --- .github/workflows/check.yml | 1 - .gitignore | 4 +- Cargo.toml | 66 +- rosu-v2/LICENSE => LICENSE | 0 generate-mods/Cargo.toml | 11 - generate-mods/README.md | 7 - generate-mods/src/error.rs | 11 - generate-mods/src/lib.rs | 977 -- generate-mods/src/main.rs | 50 - generate-mods/src/model.rs | 526 - generate-mods/src/writer.rs | 63 - rosu-v2/Cargo.toml | 55 - rosu-v2/src/model/mode.rs | 113 - rosu-v2/src/model/mods/acronym.rs | 111 - rosu-v2/src/model/mods/generated_mods.rs | 12180 ---------------- rosu-v2/src/model/mods/intermode.rs | 863 -- rosu-v2/src/model/mods/intersection.rs | 107 - rosu-v2/src/model/mods/iter.rs | 98 - rosu-v2/src/model/mods/macros.rs | 80 - rosu-v2/src/model/mods/manual.rs | 47 - rosu-v2/src/model/mods/mod.rs | 847 -- rosu-v2/src/model/mods/mode_as_seed.rs | 87 - {rosu-v2/src => src}/client/builder.rs | 0 {rosu-v2/src => src}/client/mod.rs | 0 {rosu-v2/src => src}/client/token.rs | 0 {rosu-v2/src => src}/error.rs | 0 {rosu-v2/src => src}/lib.rs | 26 +- {rosu-v2/src => src}/metrics.rs | 0 {rosu-v2/src => src}/model/beatmap.rs | 0 {rosu-v2/src => src}/model/comments.rs | 0 {rosu-v2/src => src}/model/event.rs | 0 {rosu-v2/src => src}/model/forum.rs | 0 {rosu-v2/src => src}/model/grade.rs | 0 {rosu-v2/src => src}/model/kudosu.rs | 0 {rosu-v2/src => src}/model/matches.rs | 14 +- {rosu-v2/src => src}/model/mod.rs | 6 +- src/model/mods.rs | 4 + {rosu-v2/src => src}/model/news.rs | 0 {rosu-v2/src => src}/model/ranking.rs | 0 {rosu-v2/src => src}/model/score.rs | 7 +- .../src => src}/model/seasonal_backgrounds.rs | 0 {rosu-v2/src => src}/model/serde_util.rs | 0 {rosu-v2/src => src}/model/user.rs | 0 {rosu-v2/src => src}/model/wiki.rs | 0 {rosu-v2/src => src}/request/beatmap.rs | 0 {rosu-v2/src => src}/request/comments.rs | 0 {rosu-v2/src => src}/request/event.rs | 0 {rosu-v2/src => src}/request/forum.rs | 0 {rosu-v2/src => src}/request/matches.rs | 0 {rosu-v2/src => src}/request/mod.rs | 0 {rosu-v2/src => src}/request/news.rs | 0 {rosu-v2/src => src}/request/ranking.rs | 0 {rosu-v2/src => src}/request/replay.rs | 0 .../request/seasonal_backgrounds.rs | 0 {rosu-v2/src => src}/request/serialize.rs | 0 {rosu-v2/src => src}/request/user.rs | 0 {rosu-v2/src => src}/request/wiki.rs | 0 {rosu-v2/src => src}/routing.rs | 0 {rosu-v2/tests => tests}/requests.rs | 5 +- {rosu-v2/tests => tests}/serde.rs | 4 +- 60 files changed, 102 insertions(+), 16268 deletions(-) rename rosu-v2/LICENSE => LICENSE (100%) delete mode 100644 generate-mods/Cargo.toml delete mode 100644 generate-mods/README.md delete mode 100644 generate-mods/src/error.rs delete mode 100644 generate-mods/src/lib.rs delete mode 100644 generate-mods/src/main.rs delete mode 100644 generate-mods/src/model.rs delete mode 100644 generate-mods/src/writer.rs delete mode 100644 rosu-v2/Cargo.toml delete mode 100644 rosu-v2/src/model/mode.rs delete mode 100644 rosu-v2/src/model/mods/acronym.rs delete mode 100644 rosu-v2/src/model/mods/generated_mods.rs delete mode 100644 rosu-v2/src/model/mods/intermode.rs delete mode 100644 rosu-v2/src/model/mods/intersection.rs delete mode 100644 rosu-v2/src/model/mods/iter.rs delete mode 100644 rosu-v2/src/model/mods/macros.rs delete mode 100644 rosu-v2/src/model/mods/manual.rs delete mode 100644 rosu-v2/src/model/mods/mod.rs delete mode 100644 rosu-v2/src/model/mods/mode_as_seed.rs rename {rosu-v2/src => src}/client/builder.rs (100%) rename {rosu-v2/src => src}/client/mod.rs (100%) rename {rosu-v2/src => src}/client/token.rs (100%) rename {rosu-v2/src => src}/error.rs (100%) rename {rosu-v2/src => src}/lib.rs (93%) rename {rosu-v2/src => src}/metrics.rs (100%) rename {rosu-v2/src => src}/model/beatmap.rs (100%) rename {rosu-v2/src => src}/model/comments.rs (100%) rename {rosu-v2/src => src}/model/event.rs (100%) rename {rosu-v2/src => src}/model/forum.rs (100%) rename {rosu-v2/src => src}/model/grade.rs (100%) rename {rosu-v2/src => src}/model/kudosu.rs (100%) rename {rosu-v2/src => src}/model/matches.rs (99%) rename {rosu-v2/src => src}/model/mod.rs (98%) create mode 100644 src/model/mods.rs rename {rosu-v2/src => src}/model/news.rs (100%) rename {rosu-v2/src => src}/model/ranking.rs (100%) rename {rosu-v2/src => src}/model/score.rs (99%) rename {rosu-v2/src => src}/model/seasonal_backgrounds.rs (100%) rename {rosu-v2/src => src}/model/serde_util.rs (100%) rename {rosu-v2/src => src}/model/user.rs (100%) rename {rosu-v2/src => src}/model/wiki.rs (100%) rename {rosu-v2/src => src}/request/beatmap.rs (100%) rename {rosu-v2/src => src}/request/comments.rs (100%) rename {rosu-v2/src => src}/request/event.rs (100%) rename {rosu-v2/src => src}/request/forum.rs (100%) rename {rosu-v2/src => src}/request/matches.rs (100%) rename {rosu-v2/src => src}/request/mod.rs (100%) rename {rosu-v2/src => src}/request/news.rs (100%) rename {rosu-v2/src => src}/request/ranking.rs (100%) rename {rosu-v2/src => src}/request/replay.rs (100%) rename {rosu-v2/src => src}/request/seasonal_backgrounds.rs (100%) rename {rosu-v2/src => src}/request/serialize.rs (100%) rename {rosu-v2/src => src}/request/user.rs (100%) rename {rosu-v2/src => src}/request/wiki.rs (100%) rename {rosu-v2/src => src}/routing.rs (100%) rename {rosu-v2/tests => tests}/requests.rs (99%) rename {rosu-v2/tests => tests}/serde.rs (99%) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 66a7de9..1f87cf7 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -79,4 +79,3 @@ jobs: --feature-powerset --no-dev-deps --optional-deps metrics --group-features default,cache,macros - --workspace --exclude generate-mods diff --git a/.gitignore b/.gitignore index 50bcb0d..70d1b9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ /target .env -/.idea Cargo.lock -/*/Cargo.lock output.* expanded.* -/*/tests/custom.rs +/tests/custom.rs diff --git a/Cargo.toml b/Cargo.toml index cfee64a..8283637 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,55 @@ -[workspace] -members = [ - "rosu-v2", - "generate-mods" -] -resolver = "2" - -[workspace.package] -authors = ["MaxOhn "] -edition = "2021" -license = "MIT" +[package] +name = "rosu-v2" +version = "0.8.0" +description = "An osu! API v2 wrapper" +readme = "README.md" +keywords = ["osu", "api", "wrapper"] +repository = "https://github.com/MaxOhn/rosu-v2" +documentation = "https://docs.rs/rosu-v2/" +authors = ["MaxOhn "] +edition = "2021" +license = "MIT" + +# --- Features --- + +[features] +default = ["cache", "macros"] +cache = ["dashmap"] +macros = ["rosu-mods/macros"] +replay = ["osu-db"] +serialize = [] + +# --- Dependencies --- + +[dependencies] +bytes = { version = "1.0", default-features = false } +futures = { version = "0.3", default-features = false } +leaky-bucket-lite = { version = "0.5" } +log = { version = "0.4", default-features = false } +hyper = { version = "0.14", default-features = false, features = ["client"] } +hyper-rustls = { version = "0.24.1", default-features = false, features = ["http1", "http2", "native-tokio"] } +itoa = { version = "1.0.9" } +rosu-mods = { path = "../rosu-mods", default-features = false, features = ["serde"] } +serde = { version = "1.0.203", default-features = false, features = ["derive"] } +serde_json = { version = "1.0", default-features = false, features = ["std", "raw_value"] } +serde_urlencoded = { version = "0.7.1" } +smallstr = { version = "0.3.0", features = ["serde"] } +thiserror = { version = "1.0" } +time = { version = "0.3", features = ["formatting", "parsing"] } +tokio = { version = "1.0", default-features = false, features = ["macros"] } +url = { version = "2.0", default-features = false } + +# --- Feature dependencies --- + +dashmap = { version = "5.1", default-features = false, optional = true } +osu-db = { version = "0.3.0", optional = true } +metrics = { version = "0.21.1", optional = true } + +# --- Dev dependencies --- + +[dev-dependencies] +dotenv = { version = "0.15" } +env_logger = { version = "0.9" } +eyre = { version = "0.6" } +once_cell = { version = "1.7" } +tokio = { version = "1.0", default-features = false, features = ["rt", "macros"] } diff --git a/rosu-v2/LICENSE b/LICENSE similarity index 100% rename from rosu-v2/LICENSE rename to LICENSE diff --git a/generate-mods/Cargo.toml b/generate-mods/Cargo.toml deleted file mode 100644 index eecbeb1..0000000 --- a/generate-mods/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "generate-mods" -version = "0.1.0" -edition = "2021" - -[dependencies] -itoa = { version = "1.0" } -minreq = { version = "2.10.0", default-features = false, features = ["https-rustls"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = { version = "1.0", features = ["raw_value"] } -thiserror = { version = "1.0" } diff --git a/generate-mods/README.md b/generate-mods/README.md deleted file mode 100644 index bf5ba88..0000000 --- a/generate-mods/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# generate-mods - -Binary to generate rust types based on osu!'s [mods.json](https://github.com/ppy/osu-web/blob/master/database/mods.json). - -- Requests the file -- Processes its content -- Writes types into `generated_mods.rs` \ No newline at end of file diff --git a/generate-mods/src/error.rs b/generate-mods/src/error.rs deleted file mode 100644 index 0232948..0000000 --- a/generate-mods/src/error.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub type GenResult = Result; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("minreq error")] - Http(#[from] minreq::Error), - #[error("io error")] - Io(#[from] std::io::Error), - #[error("json error")] - Json(#[from] serde_json::Error), -} diff --git a/generate-mods/src/lib.rs b/generate-mods/src/lib.rs deleted file mode 100644 index e093341..0000000 --- a/generate-mods/src/lib.rs +++ /dev/null @@ -1,977 +0,0 @@ -use std::collections::HashMap; - -use itoa::Buffer; - -pub use self::{error::GenResult, model::RulesetMods, writer::Writer}; - -mod error; -mod model; -mod writer; - -pub fn specify_preamble(writer: &mut Writer, url: &str, disclaimer: &str) -> GenResult { - writer.write(disclaimer)?; - writer.write( - "\n\ - //!\n\ - //! See <", - )?; - writer.write(url)?; - - writer.write( - ">\n\n\ - use std::{\ - borrow::Borrow,\ - cmp::Ordering,\ - num::NonZeroU8,\ - fmt::{Display, Formatter, Result as FmtResult},\ - };\n\n", - )?; - writer.write( - "use serde::{\ - Deserialize,\ - de::{value::MapAccessDeserializer, Deserializer, DeserializeSeed, Error as DeError, IgnoredAny, MapAccess, Visitor}\ - };", - )?; - writer.write("use serde_json::value::RawValue;")?; - writer.write( - "\nuse crate::model::{\ - mods::{Acronym, ModeAsSeed},\ - GameMode,\ - };", - )?; - - Ok(()) -} - -pub fn define_gamemod_structs( - rulesets: &[RulesetMods], - writer: &mut Writer, - itoa_buf: &mut Buffer, -) -> GenResult { - for ruleset in rulesets.iter() { - for gamemod in ruleset.mods.iter() { - gamemod.write(writer, itoa_buf)?; - } - } - - write_unknown_mod(writer)?; - - Ok(()) -} - -pub fn define_gamemod_kind(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - // hard-coded to simplify Ord implementation - let expected = [ - "DifficultyReduction", - "DifficultyIncrease", - "Conversion", - "Automation", - "Fun", - "System", - ]; - - for ruleset in rulesets.iter() { - for gamemod in ruleset.mods.iter() { - if !expected.contains(&&*gamemod.kind) { - panic!("unexpected GameModKind `{}`", gamemod.kind); - } - } - } - - writer.write( - "/// The different types of a [`GameMod`]\n\ - #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\ - #[cfg_attr(feature = \"serialize\", derive(serde::Serialize))]\ - pub enum GameModKind {\ - DifficultyReduction,\ - DifficultyIncrease,\ - Conversion,\ - Automation,\ - Fun,\ - System,\ - }", - ) -} - -pub fn define_gamemod_intermode( - rulesets: &[RulesetMods], - writer: &mut Writer, - itoa_buf: &mut Buffer, -) -> GenResult { - let mut mods = rulesets - .iter() - .flat_map(|ruleset| { - let suffix_len = ruleset.name.as_capitalized_str().len(); - - ruleset.mods.iter().map(move |gamemod| { - let name = &gamemod.name[..gamemod.name.len() - suffix_len]; - let bits = gamemod.bits(); - let kind = gamemod.kind.as_ref(); - - (name, (bits, gamemod.acronym, kind)) - }) - }) - .collect::>() - .into_iter() - .collect::>(); - - mods.sort_unstable_by(|(a, ..), (b, ..)| a.cmp(b)); - - writer.write( - "/// The kind of a [`GameMod`] when the mode is ignored\n\ - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]\ - #[non_exhaustive]\ - pub enum GameModIntermode {", - )?; - - for (name, _) in mods.iter() { - writer.write(*name)?; - writer.write(b',')?; - } - - writer.write("Unknown(UnknownMod),")?; - writer.write(b'}')?; - - writer.write( - "impl GameModIntermode {\ - /// The [`Acronym`] of this [`GameModIntermode`]\n\ - pub const fn acronym(&self) -> Acronym {\ - unsafe { match self {", - )?; - - for (name, (_, acronym, _)) in mods.iter() { - writer.write("Self::")?; - writer.write(*name)?; - writer.write(" => ")?; - acronym.write(writer)?; - writer.write(b',')?; - } - - writer.write( - "\ - Self::Unknown(m) => m.acronym(),\ - }\ - }\ - }\ - /// Bit value of the [`GameModIntermode`]\n\ - ///\n\ - /// See \n\ - pub const fn bits(self) -> Option {\ - match self {", - )?; - - for (name, (bits, ..)) in mods.iter() { - writer.write("Self::")?; - writer.write(*name)?; - writer.write(" => ")?; - - match bits { - Some(bits) => { - writer.write("Some(")?; - writer.write(itoa_buf.format(*bits))?; - writer.write(b')')?; - } - None => writer.write("None")?, - } - - writer.write(b',')?; - } - - writer.write( - "\ - Self::Unknown(_) => None,\ - }\ - }\ - /// The [`GameModKind`] of this [`GameModIntermode`]\n\ - pub const fn kind(&self) -> GameModKind {\ - match self {", - )?; - - for (name, (.., kind)) in mods.iter() { - writer.write("Self::")?; - writer.write(*name)?; - writer.write(" => GameModKind::")?; - writer.write(*kind)?; - writer.write(b',')?; - } - - writer.write( - "\ - Self::Unknown(_) => GameModKind::System,\ - }\ - }\ - /// Parse an [`Acronym`] into a [`GameModIntermode`]\n\ - pub fn from_acronym(acronym: Acronym) -> Self {\ - match acronym.as_str() {", - )?; - - for (name, (_, acronym, _)) in mods.iter() { - writer.write(b'"')?; - writer.write(acronym.as_str())?; - writer.write("\" => Self::")?; - writer.write(*name)?; - writer.write(b',')?; - } - - writer.write( - "\ - _ => Self::Unknown(UnknownMod { acronym }),\ - }\ - }\ - }", - )?; - - writer.write( - "impl PartialOrd for GameModIntermode {\ - fn partial_cmp(&self, other: &Self) -> Option {\ - Some(self.cmp(other))\ - }\ - }\ - impl Ord for GameModIntermode {\ - fn cmp(&self, other: &Self) -> Ordering {\ - match (self.bits(), other.bits()) {\ - (Some(self_bits), Some(other_bits)) => self_bits.cmp(&other_bits),\ - (Some(_), None) => Ordering::Less,\ - (None, Some(_)) => Ordering::Greater,\ - (None, None) => self.acronym().as_str().cmp(other.acronym().as_str()),\ - }\ - }\ - }\ - impl Display for GameModIntermode {\ - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {\ - f.write_str(self.acronym().as_str())\ - }\ - }\ - impl From<&GameModIntermode> for GameModIntermode {\ - fn from(gamemod: &GameModIntermode) -> Self {\ - *gamemod\ - }\ - }\ - impl From for GameModIntermode {\ - fn from(gamemod: GameMod) -> Self {\ - gamemod.intermode()\ - }\ - }\ - #[cfg(feature = \"serialize\")]\ - impl serde::Serialize for GameModIntermode {\ - fn serialize(&self, s: S) -> Result {\ - s.serialize_str(self.acronym().as_str())\ - }\ - }", - ) -} - -pub fn define_gamemod_order( - rulesets: &[RulesetMods], - writer: &mut Writer, - itoa_buf: &mut Buffer, -) -> GenResult { - writer.write( - "#[derive(Copy, Clone, PartialEq, Eq)]\ - pub(crate) struct GameModOrder {\ - mode: GameMode,\ - index: Option,\ - intermode: GameModIntermode,\ - }\ - impl From<&GameMod> for GameModOrder {\ - fn from(gamemod: &GameMod) -> Self {\ - const fn inner(gamemod: &GameMod) -> GameModOrder {\ - macro_rules! arm {\ - ($mode:ident, $gamemod:ident, Some($discriminant:literal), $intermode:ident) => {\ - arm!(\ - $mode,\ - $gamemod,\ - Some(unsafe { NonZeroU8::new_unchecked($discriminant) }),\ - $intermode,\ - )\ - };\ - ($mode:ident, $gamemod:ident, $index:expr, $intermode:ident $(,)?) => {\ - GameModOrder {\ - mode: GameMode::$mode,\ - index: $index,\ - intermode: GameModIntermode::$intermode,\ - }\ - };\ - }\ - match gamemod {", - )?; - - for ruleset in rulesets { - let ruleset_str = ruleset.name.as_capitalized_str(); - - for gamemod in ruleset.mods.iter() { - writer.write("GameMod::")?; - writer.write(&gamemod.name)?; - writer.write("(_) => arm!(")?; - writer.write(ruleset_str)?; - writer.write(b',')?; - writer.write(&gamemod.name)?; - writer.write(b',')?; - - match gamemod.discriminant() { - Some(discriminant) => { - writer.write("Some(")?; - writer.write(itoa_buf.format(discriminant))?; - writer.write(b')')?; - } - None => { - writer.write("None")?; - } - } - - let intermode = &gamemod.name[..gamemod.name.len() - ruleset_str.len()]; - writer.write(b',')?; - writer.write(intermode)?; - writer.write("),")?; - } - - writer.write("GameMod::Unknown")?; - writer.write(ruleset_str)?; - writer.write( - "(m) => GameModOrder {\ - mode: GameMode::", - )?; - writer.write(ruleset_str)?; - writer.write( - ",\ - index: None,\ - intermode: GameModIntermode::Unknown(*m),\ - },", - )?; - } - - writer.write( - "\ - }\ - }\ - inner(gamemod)\ - }\ - }\ - impl PartialOrd for GameModOrder {\ - fn partial_cmp(&self, other: &Self) -> Option {\ - Some(self.cmp(other))\ - }\ - }\ - impl Ord for GameModOrder {\ - fn cmp(&self, other: &Self) -> Ordering {\ - self.mode.cmp(&other.mode)\ - .then_with(|| match (self.index, other.index) {\ - (Some(self_idx), Some(other_idx)) => self_idx.cmp(&other_idx),\ - (Some(_), None) => Ordering::Less,\ - (None, Some(_)) => Ordering::Greater,\ - (None, None) => self\ - .intermode\ - .acronym()\ - .as_str()\ - .cmp(other.intermode.acronym().as_str()),\ - })\ - }\ - }\ - impl PartialEq for GameModOrder {\ - fn eq(&self, other: &GameModIntermode) -> bool {\ - self.intermode.eq(other)\ - }\ - }\ - impl Borrow for GameModOrder {\ - fn borrow(&self) -> &GameModIntermode {\ - &self.intermode\ - }\ - }", - ) -} - -pub fn define_gamemod_enum(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "/// A single game mod\n\ - #[derive(Clone, Debug, PartialEq)]\ - #[non_exhaustive]\ - pub enum GameMod {", - )?; - - for ruleset in rulesets { - for gamemod in ruleset.mods.iter() { - writer.write(&gamemod.name)?; - writer.write(b'(')?; - writer.write(&gamemod.name)?; - writer.write("),")?; - } - - writer.write("Unknown")?; - writer.write(ruleset.name.as_capitalized_str())?; - writer.write("(UnknownMod),")?; - } - - writer.write(b'}') -} - -pub fn define_gamemod_fns(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write("impl GameMod {")?; - - define_gamemod_fn_new(rulesets, writer)?; - define_gamemod_fn_acronym(rulesets, writer)?; - define_gamemod_fn_incompatible_mods(rulesets, writer)?; - define_gamemod_fn_description(rulesets, writer)?; - define_gamemod_fn_kind(rulesets, writer)?; - define_gamemod_fn_bits(rulesets, writer)?; - define_gamemod_fn_mode(rulesets, writer)?; - define_gamemod_fn_intermode(rulesets, writer)?; - - writer.write(b'}') -} - -fn write_unknown_mod(writer: &mut Writer) -> GenResult { - writer.write( - "/// Any mod unknown to `rosu-v2`\n\ - #[derive(Copy, Eq, Clone, Debug, PartialEq, PartialOrd, Ord, Hash)]\ - pub struct UnknownMod {\ - pub acronym: Acronym,\ - }\ - impl UnknownMod {\ - /// The default [`Acronym`] for an unknown mod without specific\n\ - /// acronym.\n\ - pub const UNKNOWN_ACRONYM: Acronym = unsafe { Acronym::from_str_unchecked(\"??\") };\n\ - /// A custom [`Acronym`] for any unknown mod\n\ - pub const fn acronym(self) -> Acronym {\ - self.acronym\ - }\ - /// Returns an empty iterator\n\ - pub const fn incompatible_mods() -> std::iter::Empty {\ - std::iter::empty()\ - }\ - /// A custom description for any unknown mod\n\ - pub const fn description() -> &'static str {\ - \"Any mod unknown to the rosu-v2 crate\"\ - }\ - /// A manually assigned [`GameModKind`] for any unknown mod\n\ - pub const fn kind() -> GameModKind {\ - GameModKind::System\ - }\ - }\ - impl Default for UnknownMod {\ - fn default() -> Self {\ - Self {\ - acronym: Self::UNKNOWN_ACRONYM,\ - }\ - }\ - }\ - impl<'de> Deserialize<'de> for UnknownMod {\ - fn deserialize>(d: D) -> Result {\ - struct UnknownModVisitor;\ - impl<'de> Visitor<'de> for UnknownModVisitor {\ - type Value = UnknownMod;\ - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {\ - f.write_str(\"any unknown mod\")\ - }\ - fn visit_map>(self, mut map: A) -> Result {\ - while map.next_entry::()?.is_some() {}\ - Ok(UnknownMod { acronym: UnknownMod::UNKNOWN_ACRONYM })\ - }\ - }\ - d.deserialize_map(UnknownModVisitor)\ - }\ - }\ - #[cfg(feature = \"serialize\")]\ - impl serde::Serialize for UnknownMod {\ - fn serialize(&self, s: S) -> Result {\ - s.serialize_map(Some(0)).and_then(serde::ser::SerializeMap::end)\ - }\ - }" - ) -} - -fn define_gamemod_fn_new(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "/// Create a new [`GameMod`]\n\ - pub fn new(acronym: &str, mode: GameMode) -> Self {\ - match (acronym, mode) {", - )?; - - for ruleset in rulesets { - let ruleset_str = ruleset.name.as_capitalized_str(); - - for gamemod in ruleset.mods.iter() { - writer.write("(\"")?; - writer.write(gamemod.acronym.as_str())?; - writer.write("\", GameMode::")?; - writer.write(ruleset_str)?; - writer.write(") => Self::")?; - writer.write(&gamemod.name)?; - writer.write("(Default::default()),")?; - } - } - - writer.write( - "_ => {\ - let acronym = ::from_str(acronym)\ - .unwrap_or(UnknownMod::UNKNOWN_ACRONYM);\ - let unknown = UnknownMod { acronym };\ - match mode {", - )?; - - for ruleset in rulesets { - let ruleset_str = ruleset.name.as_capitalized_str(); - writer.write("GameMode::")?; - writer.write(ruleset_str)?; - writer.write(" => GameMod::Unknown")?; - writer.write(ruleset_str)?; - writer.write("(unknown),")?; - } - - writer.write( - "\ - }\ - }\ - }\ - }", - ) -} - -fn define_gamemod_fn_acronym(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "/// The acronym of this [`GameMod`]\n\ - pub const fn acronym(&self) -> Acronym {\ - match self {", - )?; - - for ruleset in rulesets { - for gamemod in ruleset.mods.iter() { - writer.write("Self::")?; - writer.write(&gamemod.name)?; - writer.write("(_) => ")?; - writer.write(&gamemod.name)?; - writer.write("::acronym(),")?; - } - } - - let mut rulesets_iter = rulesets.iter(); - - if let Some(ruleset) = rulesets_iter.next() { - writer.write("Self::Unknown")?; - writer.write(ruleset.name.as_capitalized_str())?; - writer.write("(m)")?; - - for ruleset in rulesets_iter { - writer.write(" | Self::Unknown")?; - writer.write(ruleset.name.as_capitalized_str())?; - writer.write("(m)")?; - } - - writer.write(" => m.acronym(),")?; - } - - writer.write( - "\ - }\ - }", - ) -} - -fn define_gamemod_fn_incompatible_mods(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "/// List of [`Acronym`] for mods that are incompatible with this [`GameMod`]\n\ - pub fn incompatible_mods(&self) -> Box<[Acronym]> {\ - match self {", - )?; - - for ruleset in rulesets { - for gamemod in ruleset.mods.iter() { - writer.write("Self::")?; - writer.write(&gamemod.name)?; - writer.write("(_) => ")?; - writer.write(&gamemod.name)?; - writer.write("::incompatible_mods().collect(),")?; - } - } - - writer.write("_ => UnknownMod::incompatible_mods().collect(),")?; - - writer.write("}}") -} - -fn define_gamemod_fn_description(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "/// The description of this [`GameMod`]\n\ - pub const fn description(&self) -> &'static str {\ - match self {", - )?; - - for ruleset in rulesets { - for gamemod in ruleset.mods.iter() { - writer.write("Self::")?; - writer.write(&gamemod.name)?; - writer.write("(_) => ")?; - writer.write(&gamemod.name)?; - writer.write("::description(),")?; - } - } - - writer.write("_ => UnknownMod::description(),")?; - - writer.write("}}") -} - -fn define_gamemod_fn_kind(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "/// The [`GameModKind`] of this [`GameMod`]\n\ - pub const fn kind(&self) -> GameModKind {\ - match self {", - )?; - - for ruleset in rulesets { - for gamemod in ruleset.mods.iter() { - writer.write("Self::")?; - writer.write(&gamemod.name)?; - writer.write("(_) => ")?; - writer.write(&gamemod.name)?; - writer.write("::kind(),")?; - } - } - - writer.write("_ => UnknownMod::kind(),")?; - - writer.write( - "\ - }\ - }", - ) -} - -fn define_gamemod_fn_bits(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "/// Optional bit value of this [`GameMod`]\n\ - ///\n\ - /// See \n\ - pub const fn bits(&self) -> Option {\ - match self {", - )?; - - for ruleset in rulesets { - for gamemod in ruleset.mods.iter() { - if gamemod.bits().is_some() { - writer.write("Self::")?; - writer.write(&gamemod.name)?; - writer.write("(_) => Some(")?; - writer.write(&gamemod.name)?; - writer.write("::bits()),")?; - } - } - } - - writer.write( - "\ - _ => None,\ - }\ - }", - ) -} - -fn define_gamemod_fn_intermode(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "/// The kind of a [`GameMod`] when ignoring the mode\n\ - pub const fn intermode(&self) -> GameModIntermode {\ - match self {", - )?; - - for ruleset in rulesets { - let ruleset_str = ruleset.name.as_capitalized_str(); - - for gamemod in ruleset.mods.iter() { - let intermode = &gamemod.name[..gamemod.name.len() - ruleset_str.len()]; - - writer.write("Self::")?; - writer.write(&gamemod.name)?; - writer.write("(_) => GameModIntermode::")?; - writer.write(intermode)?; - writer.write(b',')?; - } - } - - let mut ruleset_iter = rulesets.iter(); - - if let Some(ruleset) = ruleset_iter.next() { - writer.write("Self::Unknown")?; - writer.write(ruleset.name.as_capitalized_str())?; - writer.write("(m)")?; - - for ruleset in ruleset_iter { - writer.write(" | Self::Unknown")?; - writer.write(ruleset.name.as_capitalized_str())?; - writer.write("(m)")?; - } - - writer.write(" => GameModIntermode::Unknown(*m),")?; - } - - writer.write( - "\ - }\ - }", - ) -} - -fn define_gamemod_fn_mode(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "/// The [`GameMode`] of a [`GameMod`]\n\ - pub const fn mode(&self) -> GameMode {\ - match self {", - )?; - - for ruleset in rulesets { - for gamemod in ruleset.mods.iter() { - writer.write("Self::")?; - writer.write(&gamemod.name)?; - writer.write("(_) | ")?; - } - - let ruleset_str = ruleset.name.as_capitalized_str(); - writer.write("Self::Unknown")?; - writer.write(ruleset_str)?; - writer.write("(_) => GameMode::")?; - writer.write(ruleset_str)?; - writer.write(b',')?; - } - - writer.write("}}") -} - -pub fn impl_gamemod_traits(writer: &mut Writer) -> GenResult { - writer.write( - "impl PartialOrd for GameMod {\ - fn partial_cmp(&self, other: &Self) -> Option {\ - self\ - .bits()\ - .zip(other.bits())\ - .map(|(self_bits, other_bits)| self_bits.cmp(&other_bits))\ - }\ - }", - ) -} - -pub fn impl_serde(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - writer.write( - "struct GameModSettings<'a> {\ - acronym: &'a str,\ - mode: GameMode,\ - }\ - impl<'de> DeserializeSeed<'de> for GameModSettings<'de> {\ - type Value = >::Value;\ - fn deserialize>(self, d: D) -> Result {\ - d.deserialize_any(self)\ - }\ - }", - )?; - - writer.write( - "impl<'de> Visitor<'de> for GameModSettings<'de> {\ - type Value = GameMod;\ - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {\ - f.write_str(\"GameMod settings\")\ - }\ - fn visit_map>(self, map: A) -> Result {\ - let d = MapAccessDeserializer::new(map);\ - let res = match (self.acronym, self.mode) {", - )?; - - for ruleset in rulesets { - let ruleset_str = ruleset.name.as_capitalized_str(); - - for gamemod in ruleset.mods.iter() { - writer.write("(\"")?; - writer.write(gamemod.acronym.as_str())?; - writer.write("\", GameMode::")?; - writer.write(ruleset_str)?; - writer.write(") => GameMod::")?; - writer.write(&gamemod.name)?; - writer.write("(Deserialize::deserialize(d)?),")?; - } - } - - writer.write( - "_ => {\ - let acronym = ::from_str(self.acronym).map_err(DeError::custom)?;\n\ - // All fields are specified already but we still want to clear\n\ - // out content from the deserializer.\n\ - #[allow(clippy::needless_update)]\ - let unknown = UnknownMod {\ - acronym,\ - ..Deserialize::deserialize(d)?\ - };\ - match self.mode {", - )?; - - for ruleset in rulesets { - let ruleset_str = ruleset.name.as_capitalized_str(); - writer.write("GameMode::")?; - writer.write(ruleset_str)?; - writer.write(" => GameMod::Unknown")?; - writer.write(ruleset_str)?; - writer.write("(unknown),")?; - } - - writer.write( - "\ - }\ - }\ - };\ - Ok(res)\ - }\ - }", - )?; - - writer.write( - "impl<'de> Visitor<'de> for ModeAsSeed {\ - type Value = GameMod;\ - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {\ - f.write_str(\"a GameMod\")\ - }\ - fn visit_str(self, v: &str) -> Result {\ - Ok(GameMod::new(v, self.mode))\ - }\ - fn visit_map>(self, mut map: A) -> Result {\ - // Using RawValue avoids an allocation since serde_json generally\n\ - // deserializes into String to handle escaped characters.\n\ - let key = map.next_key::<&RawValue>()?.map(RawValue::get);\ - let Some(r#\"\"acronym\"\"#) = key else {\ - return Err(DeError::custom(\"expected `acronym` as first field\"));\ - };\ - let acronym: &'de str = map.next_value()?;\ - let mut gamemod = None;\ - while let Some(key) = map.next_key::<&str>()? {\ - if key == \"settings\" {\ - gamemod = Some(map.next_value_seed(GameModSettings { acronym, mode: self.mode })?);\ - } else {\ - let _: IgnoredAny = map.next_value()?;\ - }\ - }\ - Ok(gamemod.unwrap_or_else(|| GameMod::new(acronym, self.mode)))\ - }\ - }", - )?; - - writer.write( - "#[cfg(feature = \"serialize\")]\ - impl serde::Serialize for GameMod {\ - fn serialize(&self, s: S) -> Result {\ - use serde::ser::SerializeMap;\ - let mut s = s.serialize_map(None)?;\ - s.serialize_entry(\"acronym\", self.acronym().as_str())?;\ - match self {", - )?; - - for ruleset in rulesets { - for gamemod in ruleset.mods.iter() { - if gamemod.settings.is_empty() { - continue; - } - - writer.write("Self::")?; - writer.write(&gamemod.name)?; - writer.write( - "\ - (m) => {\ - let has_some = ", - )?; - - let mut settings = gamemod.settings.iter(); - - if let Some(setting) = settings.next() { - writer.write("m.")?; - writer.write(&setting.name)?; - writer.write(".is_some()")?; - - for setting in settings { - writer.write(" || m.")?; - writer.write(&setting.name)?; - writer.write(".is_some()")?; - } - } - - writer.write( - "\ - ;\ - if has_some {\ - s.serialize_entry(\"settings\", m)?;\ - }\ - },", - )?; - } - } - - writer.write( - "\ - _ => {},\ - }\ - s.end()\ - }\ - }", - ) -} - -pub fn impl_macro(rulesets: &[RulesetMods], writer: &mut Writer) -> GenResult { - let mut intermodes = rulesets - .iter() - .flat_map(|ruleset| { - let ruleset_str = ruleset.name.as_capitalized_str(); - - ruleset.mods.iter().map(|gamemod| { - let intermode = &gamemod.name[..gamemod.name.len() - ruleset_str.len()]; - - (gamemod.acronym.as_str(), intermode) - }) - }) - .collect::>() - .into_iter() - .collect::>(); - - intermodes.sort_unstable(); - - writer.write( - "#[macro_export(local_inner_macros)]\ - #[doc(hidden)]\ - macro_rules! mods_inner {", - )?; - - for (acronym, gamemod) in intermodes { - writer.write_raw( - b" - ( [ $( $mode:ident )? ] ", - )?; - writer.write(acronym)?; - - writer.write_raw( - b" \ -$( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* ", - )?; - - writer.write(gamemod)?; - - writer.write_raw( - b" ) - };", - )?; - } - - writer.write_raw( - b" - ( [ $mode:ident ] ) => {{ - let _ = $crate::model::GameMode::$mode; - $crate::model::mods::GameMods::new() - }}; - ( [ $mode:ident ] $( $name:ident )* ) => { - paste::paste! {{ - #[allow(unused_mut)] - let mut mods = $crate::model::mods::GameMods::new(); - $( mods.insert($crate::model::mods::GameMod::[<$name $mode>](Default::default())); )* - mods - }} - }; - ( [] $( $name:ident )* ) => {{ - #[allow(unused_mut)] - let mut mods = $crate::model::mods::GameModsIntermode::new(); - $( mods.insert($crate::model::mods::GameModIntermode::$name); )* - mods - }}; -}", - ) -} diff --git a/generate-mods/src/main.rs b/generate-mods/src/main.rs deleted file mode 100644 index 71bac40..0000000 --- a/generate-mods/src/main.rs +++ /dev/null @@ -1,50 +0,0 @@ -use std::{fs::File, process::Command}; - -use generate_mods::*; - -const AUTOMATED_DISCLAIMER: &str = "//! This file was generated automatically. Do not modify."; -const URL: &str = "https://raw.githubusercontent.com/ppy/osu-web/master/database/mods.json"; -const OUT_FILE: &str = "./generated_mods.rs"; - -fn main() -> GenResult { - let bytes = minreq::get(URL).send()?.into_bytes(); - let mut rulesets: Vec = serde_json::from_slice(&bytes)?; - RulesetMods::process(&mut rulesets); - - let mut writer = Writer::new(File::create(OUT_FILE)?); - let mut itoa_buf = itoa::Buffer::new(); - - println!("Specifying preamble..."); - specify_preamble(&mut writer, URL, AUTOMATED_DISCLAIMER)?; - println!("Defining gamemod structs..."); - define_gamemod_structs(&rulesets, &mut writer, &mut itoa_buf)?; - println!("Defining GameModKind..."); - define_gamemod_kind(&rulesets, &mut writer)?; - println!("Defining GameModIntermode..."); - define_gamemod_intermode(&rulesets, &mut writer, &mut itoa_buf)?; - println!("Defining GameModOrder..."); - define_gamemod_order(&rulesets, &mut writer, &mut itoa_buf)?; - println!("Defining GameMod..."); - define_gamemod_enum(&rulesets, &mut writer)?; - println!("Defining GameMod methods..."); - define_gamemod_fns(&rulesets, &mut writer)?; - println!("Implement base traits for GameMod..."); - impl_gamemod_traits(&mut writer)?; - println!("Implement deserialize logic..."); - impl_serde(&rulesets, &mut writer)?; - println!("Implementing macro..."); - impl_macro(&rulesets, &mut writer)?; - - writer.flush()?; - - println!("Running formatter..."); - let output = Command::new("rustfmt").arg(OUT_FILE).output()?; - - if output.status.success() { - println!("Done formatting"); - } else { - println!("{}", String::from_utf8_lossy(&output.stderr)); - } - - Ok(()) -} diff --git a/generate-mods/src/model.rs b/generate-mods/src/model.rs deleted file mode 100644 index ddad173..0000000 --- a/generate-mods/src/model.rs +++ /dev/null @@ -1,526 +0,0 @@ -use std::{ - borrow::Cow, - fmt::{Debug, Formatter, Result as FmtResult}, -}; - -use itoa::Buffer; -use serde::{ - de::{Error as DeError, Visitor}, - Deserialize, Deserializer, -}; - -use crate::{error::GenResult, writer::Writer}; - -#[derive(Copy, Clone, Debug, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum Ruleset { - Osu, - Taiko, - #[serde(rename = "fruits")] - Catch, - Mania, -} - -impl Ruleset { - pub fn as_capitalized_str(self) -> &'static str { - match self { - Ruleset::Osu => "Osu", - Ruleset::Taiko => "Taiko", - Ruleset::Catch => "Catch", - Ruleset::Mania => "Mania", - } - } -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct RulesetMods { - pub name: Ruleset, - pub mods: Box<[GameMod]>, -} - -impl RulesetMods { - pub fn process(rulesets: &mut [Self]) { - for ruleset in rulesets.iter_mut() { - ruleset.process_mod_names(); - - // make sure no gamemod excludes itself explicitly - for gamemod in ruleset.mods.iter_mut() { - gamemod - .incompatible_mods - .retain(|incompatible| incompatible != &gamemod.acronym); - } - } - } - - /// Removes whitespace and adds the mode as suffix - fn process_mod_names(&mut self) { - for gamemod in self.mods.iter_mut() { - let match_indices = gamemod.name.match_indices(' '); - - let mut res = Cow::default(); - let mut last_start = 0; - - unsafe { - for (index, matched) in match_indices { - res += gamemod.name.get_unchecked(last_start..index); - - last_start = index + matched.len(); - } - - res += gamemod.name.get_unchecked(last_start..); - } - - let mut name = res.into_owned(); - name.push_str(self.name.as_capitalized_str()); - gamemod.name = name.into_boxed_str(); - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct Acronym([u8; 3]); - -impl Acronym { - pub fn from_str(s: &str) -> Option { - match <[u8; 2]>::try_from(s.as_bytes()) { - Ok([a, b]) => Some(Self([0, a, b])), - Err(_) => s.as_bytes().try_into().map(Self).ok(), - } - } - - pub fn as_str(&self) -> &str { - let start_idx = (self.0[0] == 0) as usize; - - unsafe { std::str::from_utf8_unchecked(&self.0[start_idx..]) } - } - - pub fn write(self, writer: &mut Writer) -> GenResult { - writer.write("Acronym::from_str_unchecked(\"")?; - writer.write(self.as_str())?; - - writer.write("\")") - } -} - -impl Debug for Acronym { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str(self.as_str()) - } -} - -impl<'de> Deserialize<'de> for Acronym { - fn deserialize>(d: D) -> Result { - struct AcronymVisitor; - - impl<'de> Visitor<'de> for AcronymVisitor { - type Value = Acronym; - - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("an Acronym") - } - - fn visit_str(self, v: &str) -> Result { - Acronym::from_str(v) - .ok_or_else(|| DeError::custom(format!("invalid length for acronym `{v}`"))) - } - } - - d.deserialize_str(AcronymVisitor) - } -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct GameMod { - pub acronym: Acronym, - pub name: Box, - pub description: Box, - #[serde(rename = "Type")] - pub kind: Box, - pub settings: Box<[Setting]>, - pub incompatible_mods: Vec, -} - -impl GameMod { - pub fn bits(&self) -> Option { - match self.acronym.as_str() { - "NM" => Some(0), - "NF" => Some(1 << 0), - "EZ" => Some(1 << 1), - "TD" => Some(1 << 2), - "HD" => Some(1 << 3), - "HR" => Some(1 << 4), - "SD" => Some(1 << 5), - "DT" => Some(1 << 6), - "RX" => Some(1 << 7), - "HT" => Some(1 << 8), - "NC" => Some((1 << 6) + (1 << 9)), - "FL" => Some(1 << 10), - "AT" => Some(1 << 11), - "SO" => Some(1 << 12), - "AP" => Some(1 << 13), - "PF" => Some((1 << 5) + (1 << 14)), - "4K" => Some(1 << 15), - "5K" => Some(1 << 16), - "6K" => Some(1 << 17), - "7K" => Some(1 << 18), - "8K" => Some(1 << 19), - "FI" => Some(1 << 20), - "RD" => Some(1 << 21), - "CN" => Some(1 << 22), - "TP" => Some(1 << 23), - "9K" => Some(1 << 24), - "DS" => Some(1 << 25), - "1K" => Some(1 << 26), - "3K" => Some(1 << 27), - "2K" => Some(1 << 28), - "SV2" => Some(1 << 29), - "MR" => Some(1 << 30), - _ => None, - } - } - - pub fn discriminant(&self) -> Option { - self.bits().map(|n| (n.ilog2() as u8) + 1) - } - - pub fn write(&self, writer: &mut Writer, itoa_buf: &mut Buffer) -> GenResult { - self.define_struct(writer)?; - self.define_fns(writer, itoa_buf)?; - self.impl_serde(writer)?; - - Ok(()) - } - - fn define_struct(&self, writer: &mut Writer) -> GenResult { - writer.write("/// ")?; - writer.write(&self.description)?; - writer.write( - "\n\ - #[derive(", - )?; - - if self.settings.is_empty() { - writer.write("Copy, Eq, ")?; - } - - writer.write( - "Clone, Debug, Default, PartialEq)]\ - pub struct ", - )?; - - writer.write(&self.name)?; - writer.write(b'{')?; - - for setting in self.settings.iter() { - setting.write(writer)?; - } - - writer.write(b'}') - } - - fn define_fns(&self, writer: &mut Writer, itoa_buf: &mut Buffer) -> GenResult { - writer.write("impl ")?; - writer.write(&self.name)?; - writer.write(b'{')?; - - self.define_fn_acronym(writer)?; - self.define_fn_incompatible_mods(writer)?; - self.define_fn_description(writer)?; - self.define_fn_kind(writer)?; - self.define_fn_bits(writer, itoa_buf)?; - - writer.write(b'}') - } - - fn define_fn_acronym(&self, writer: &mut Writer) -> GenResult { - writer.write("/// The acronym of [`")?; - writer.write(&self.name)?; - writer.write( - "`]\n\ - pub const fn acronym() -> Acronym {\ - unsafe {", - )?; - - self.acronym.write(writer)?; - - writer.write( - "\ - }\ - }", - ) - } - - fn define_fn_incompatible_mods(&self, writer: &mut Writer) -> GenResult { - writer.write("/// Iterator of [`Acronym`] for mods that are incompatible with [`")?; - writer.write(&self.name)?; - writer.write( - "`]\n\ - pub fn incompatible_mods() -> impl Iterator {", - )?; - - if self.incompatible_mods.is_empty() { - writer.write("[]")?; - } else { - writer.write("unsafe { [")?; - - for incompatible in self.incompatible_mods.iter() { - incompatible.write(writer)?; - writer.write(b',')?; - } - - writer.write("] }")?; - } - - writer.write( - "\ - .into_iter()\ - }", - ) - } - - fn define_fn_description(&self, writer: &mut Writer) -> GenResult { - writer.write("/// The description of [`")?; - writer.write(&self.name)?; - writer.write( - "`]\n\ - pub const fn description() -> &'static str {\ - \"", - )?; - writer.write(&self.description)?; - - writer.write("\"}") - } - - fn define_fn_kind(&self, writer: &mut Writer) -> GenResult { - writer.write("/// The [`GameModKind`] of [`")?; - writer.write(&self.name)?; - writer.write( - "`]\n\ - pub const fn kind() -> GameModKind {\ - GameModKind::", - )?; - writer.write(&self.kind)?; - - writer.write(b'}') - } - - fn define_fn_bits(&self, writer: &mut Writer, itoa_buf: &mut Buffer) -> GenResult { - let Some(bits) = self.bits() else { - return Ok(()); - }; - writer.write("/// Bit value of [`")?; - writer.write(&self.name)?; - - writer.write( - "`]\n\ - ///\n\ - /// See \n\ - pub const fn bits() -> u32 {", - )?; - - writer.write(itoa_buf.format(bits))?; - - writer.write(b'}') - } - - fn impl_serde(&self, writer: &mut Writer) -> GenResult { - writer.write("impl<'de> Deserialize<'de> for ")?; - writer.write(&self.name)?; - writer.write( - " {\ - fn deserialize>(d: D) -> Result {\ - struct ", - )?; - writer.write(&self.name)?; - writer.write( - "Visitor;\ - impl<'de> Visitor<'de> for ", - )?; - writer.write(&self.name)?; - writer.write( - "Visitor {\ - type Value = ", - )?; - writer.write(&self.name)?; - writer.write( - ";\ - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {\ - f.write_str(\"", - )?; - writer.write(&self.name)?; - writer.write( - "\")\ - }\ - fn visit_map>(self, ", - )?; - - if self.settings.is_empty() { - writer.write(b'_')?; - } else { - writer.write("mut map")?; - } - - writer.write(": A) -> Result {")?; - - if !self.settings.is_empty() { - for setting in self.settings.iter() { - writer.write("let mut ")?; - writer.write(&setting.name)?; - writer.write(" = None;")?; - } - - writer.write( - "\ - while let Some(key) = map.next_key()? {\ - match key {", - )?; - - for setting in self.settings.iter() { - writer.write(b'"')?; - writer.write(&setting.name)?; - writer.write("\" => ")?; - writer.write(&setting.name)?; - writer.write(" = Some(map.next_value()?),")?; - } - - writer.write( - "\ - _ => {\ - let _: IgnoredAny = map.next_value()?;\ - }\ - }\ - }\ - Ok(Self::Value {", - )?; - - for setting in self.settings.iter() { - writer.write(&setting.name)?; - writer.write(b':')?; - writer.write(&setting.name)?; - writer.write(".unwrap_or_default(),")?; - } - } else { - writer.write("Ok(Self::Value {")?; - } - - writer.write( - "\ - })\ - }\ - }\ - d.deserialize_map(", - )?; - writer.write(&self.name)?; - writer.write( - "\ - Visitor)\ - }\ - }", - )?; - - writer.write( - "#[cfg(feature = \"serialize\")]\ - impl serde::Serialize for ", - )?; - writer.write(&self.name)?; - writer.write( - " {\ - fn serialize(&self, s: S) -> Result {\ - use serde::ser::SerializeMap;\ - let field_count = ", - )?; - - let mut settings = self.settings.iter(); - - if let Some(setting) = settings.next() { - writer.write("self.")?; - writer.write(&setting.name)?; - writer.write(".is_some() as usize")?; - - for setting in settings { - writer.write(" + self.")?; - writer.write(&setting.name)?; - writer.write(".is_some() as usize")?; - } - } else { - writer.write(b'0')?; - } - - writer.write( - ";\ - let ", - )?; - - if !self.settings.is_empty() { - writer.write("mut ")?; - } - - writer.write("map = s.serialize_map(Some(field_count))?;")?; - - for setting in self.settings.iter() { - writer.write( - "\ - if let Some(ref x) = self.", - )?; - writer.write(&setting.name)?; - writer.write( - " {\ - map.serialize_entry(\"", - )?; - writer.write(&setting.name)?; - writer.write( - "\ - \", x)?;\ - }", - )?; - } - - writer.write( - "\ - map.end()\ - }\ - }", - ) - } -} - -#[derive(Debug, Deserialize)] -pub struct Setting { - #[serde(rename = "Name")] - pub name: Box, - #[serde(rename = "Type")] - kind: SettingType, -} - -impl Setting { - pub fn write(&self, writer: &mut Writer) -> GenResult { - writer.write("pub ")?; - writer.write(&self.name)?; - writer.write(": Option<")?; - self.kind.write(writer)?; - - writer.write(">,") - } -} - -#[derive(Copy, Clone, Debug, Deserialize)] -enum SettingType { - #[serde(rename = "boolean")] - Bool, - #[serde(rename = "number")] - Number, - #[serde(rename = "string")] - String, -} - -impl SettingType { - pub fn write(self, writer: &mut Writer) -> GenResult { - match self { - SettingType::Bool => writer.write("bool"), - SettingType::Number => writer.write("f32"), - SettingType::String => writer.write("String"), - } - } -} diff --git a/generate-mods/src/writer.rs b/generate-mods/src/writer.rs deleted file mode 100644 index ea459ce..0000000 --- a/generate-mods/src/writer.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::{fs::File, io, slice}; - -use crate::error::GenResult; - -pub struct Writer { - inner: io::BufWriter, -} - -impl Writer { - pub fn new(file: File) -> Self { - Self { - inner: io::BufWriter::new(file), - } - } - - #[cfg_attr(debug_assertions, track_caller)] - pub fn write(&mut self, content: impl Content) -> GenResult { - let bytes = content.to_bytes(); - - debug_assert!( - bytes.windows(2).all(|window| window != [b' ', b' ']), - "Found consecutive whitespace, forgot a backslash?" - ); - - self.write_raw(bytes) - } - - pub fn write_raw(&mut self, bytes: &[u8]) -> GenResult { - io::Write::write_all(&mut self.inner, bytes).map_err(From::from) - } - - pub fn flush(&mut self) -> GenResult { - io::Write::flush(&mut self.inner).map_err(From::from) - } -} - -pub trait Content { - fn to_bytes(&self) -> &[u8]; -} - -impl Content for str { - fn to_bytes(&self) -> &[u8] { - self.as_bytes() - } -} - -impl Content for &str { - fn to_bytes(&self) -> &[u8] { - Content::to_bytes(*self) - } -} - -impl Content for &Box { - fn to_bytes(&self) -> &[u8] { - Content::to_bytes(self.as_ref()) - } -} - -impl Content for u8 { - fn to_bytes(&self) -> &[u8] { - slice::from_ref(self) - } -} diff --git a/rosu-v2/Cargo.toml b/rosu-v2/Cargo.toml deleted file mode 100644 index b8bef64..0000000 --- a/rosu-v2/Cargo.toml +++ /dev/null @@ -1,55 +0,0 @@ -[package] -name = "rosu-v2" -version = "0.8.0" -description = "An osu! API v2 wrapper" -readme = "README.md" -keywords = ["osu", "api", "wrapper"] -repository = "https://github.com/MaxOhn/rosu-v2" -documentation = "https://docs.rs/rosu-v2/" -authors.workspace = true -edition.workspace = true -license.workspace = true - -# --- Features --- - -[features] -default = ["cache", "macros"] -cache = ["dashmap"] -macros = ["paste"] -replay = ["osu-db"] -serialize = [] - -# --- Dependencies --- - -[dependencies] -bytes = { version = "1.0", default-features = false } -futures = { version = "0.3", default-features = false } -leaky-bucket-lite = { version = "0.5" } -log = { version = "0.4", default-features = false } -hyper = { version = "0.14", default-features = false, features = ["client"] } -hyper-rustls = { version = "0.24.1", default-features = false, features = ["http1", "http2", "native-tokio"] } -itoa = { version = "1.0.9" } -paste = { version = "1.0", default-features = false, optional = true } -serde = { version = "1.0", default-features = false, features = ["derive"] } -serde_json = { version = "1.0", default-features = false, features = ["std", "raw_value"] } -serde_urlencoded = { version = "0.7.1" } -smallstr = { version = "0.3.0", features = ["serde"] } -thiserror = { version = "1.0" } -time = { version = "0.3", features = ["formatting", "parsing"] } -tokio = { version = "1.0", default-features = false, features = ["macros"] } -url = { version = "2.0", default-features = false } - -# --- Feature dependencies --- - -dashmap = { version = "5.1", default-features = false, optional = true } -osu-db = { version = "0.3.0", optional = true } -metrics = { version = "0.21.1", optional = true } - -# --- Dev dependencies --- - -[dev-dependencies] -dotenv = { version = "0.15" } -env_logger = { version = "0.9" } -eyre = { version = "0.6" } -once_cell = { version = "1.7" } -tokio = { version = "1.0", default-features = false, features = ["rt", "macros"] } diff --git a/rosu-v2/src/model/mode.rs b/rosu-v2/src/model/mode.rs deleted file mode 100644 index 1727f65..0000000 --- a/rosu-v2/src/model/mode.rs +++ /dev/null @@ -1,113 +0,0 @@ -use serde::{ - de::{Error, Unexpected, Visitor}, - Deserialize, Deserializer, -}; -use std::fmt; - -/// Available game modes -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub enum GameMode { - /// osu!standard - Osu = 0, - /// osu!taiko - Taiko = 1, - /// osu!catch - Catch = 2, - /// osu!mania - Mania = 3, -} - -impl GameMode { - pub const fn as_str(self) -> &'static str { - match self { - Self::Osu => "osu", - Self::Taiko => "taiko", - Self::Catch => "fruits", - Self::Mania => "mania", - } - } -} - -impl From for GameMode { - #[inline] - fn from(mode: u8) -> Self { - match mode { - 0 => GameMode::Osu, - 1 => GameMode::Taiko, - 2 => GameMode::Catch, - 3 => GameMode::Mania, - _ => GameMode::Osu, - } - } -} - -impl Default for GameMode { - #[inline] - fn default() -> Self { - Self::Osu - } -} - -impl fmt::Display for GameMode { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -struct ModeVisitor; - -impl<'de> Visitor<'de> for ModeVisitor { - type Value = GameMode; - - #[inline] - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("a u8 or a string") - } - - fn visit_str(self, v: &str) -> Result { - let mode = match v { - "0" | "osu" | "osu!" => GameMode::Osu, - "1" | "taiko" | "tko" => GameMode::Taiko, - "2" | "ctb" | "fruits" => GameMode::Catch, - "3" | "mania" | "mna" => GameMode::Mania, - _ => { - return Err(Error::invalid_value( - Unexpected::Str(v), - &r#""0", "osu", "osu!", "1", "taiko", "tko", "2", "ctb", "fruits", "3", "mania", or "mna""#, - )) - } - }; - - Ok(mode) - } - - #[inline] - fn visit_u64(self, v: u64) -> Result { - match v { - 0 => Ok(GameMode::Osu), - 1 => Ok(GameMode::Taiko), - 2 => Ok(GameMode::Catch), - 3 => Ok(GameMode::Mania), - _ => Err(Error::invalid_value( - Unexpected::Unsigned(v), - &"0, 1, 2, or 3", - )), - } - } -} - -impl<'de> Deserialize<'de> for GameMode { - #[inline] - fn deserialize>(d: D) -> Result { - d.deserialize_any(ModeVisitor) - } -} - -#[cfg(feature = "serialize")] -impl serde::Serialize for GameMode { - #[inline] - fn serialize(&self, s: S) -> Result { - s.serialize_u8(*self as u8) - } -} diff --git a/rosu-v2/src/model/mods/acronym.rs b/rosu-v2/src/model/mods/acronym.rs deleted file mode 100644 index 6626741..0000000 --- a/rosu-v2/src/model/mods/acronym.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::{ - cmp::Ordering, - fmt::{Debug, Display, Formatter, Result as FmtResult}, - str::FromStr, -}; - -use crate::error::ParsingError; - -/// The acronym of a [`GameMod`]. -/// -/// [`GameMod`]: crate::model::mods::GameMod -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct Acronym([u8; 3]); - -impl Acronym { - /// Create an [`Acronym`] from a string. - /// - /// # Safety - /// - /// The given string must consist of two or three bytes representing capitalized ASCII letters or digits. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::Acronym; - /// - /// let hd = unsafe { Acronym::from_str_unchecked("HD") }; - /// assert_eq!(hd.as_str(), "HD"); - /// ``` - /// - /// Each of the following may lead to undefined behavior, don't do that! - /// ```rust,no_run - /// # use rosu_v2::prelude::Acronym; - /// let _ = unsafe { Acronym::from_str_unchecked("HDHR") }; - /// let _ = unsafe { Acronym::from_str_unchecked("hd") }; - /// ``` - pub const unsafe fn from_str_unchecked(s: &str) -> Self { - let array = if s.len() == 2 { - // SAFETY: `s` is guaranteed to be of length 2 - let [a, b] = unsafe { *(s.as_ptr() as *const [u8; 2]) }; - - [0, a, b] - } else { - // SAFETY: caller guarantees that `s` is of length 3 - unsafe { *(s.as_ptr() as *const [u8; 3]) } - }; - - Self(array) - } - - /// Returns the [`Acronym`] as a string. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::Acronym; - /// - /// let hd = "HD".parse::().unwrap(); - /// assert_eq!(hd.as_str(), "HD"); - /// ``` - pub fn as_str(&self) -> &str { - let start_idx = (self.0[0] == 0) as usize; - - // SAFETY: `self.0` is known to be constructed from a valid string - unsafe { std::str::from_utf8_unchecked(&self.0[start_idx..]) } - } -} - -impl Debug for Acronym { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str(self.as_str()) - } -} - -impl Display for Acronym { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - Debug::fmt(self, f) - } -} - -impl FromStr for Acronym { - type Err = ParsingError; - - /// Create an [`Acronym`] from a string. - /// - /// Errors if the acronym consists of fewer than 2 or more than 3 bytes. - fn from_str(s: &str) -> Result { - match <[u8; 2]>::try_from(s.as_bytes()) { - Ok([a, b]) => Ok(Self([0, a.to_ascii_uppercase(), b.to_ascii_uppercase()])), - Err(_) => s - .as_bytes() - .try_into() - .map(|mut array: [u8; 3]| { - array.make_ascii_uppercase(); - - Self(array) - }) - .map_err(|_| ParsingError::Acronym(Box::from(s))), - } - } -} - -impl PartialOrd for Acronym { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Acronym { - fn cmp(&self, other: &Self) -> Ordering { - self.as_str().cmp(other.as_str()) - } -} diff --git a/rosu-v2/src/model/mods/generated_mods.rs b/rosu-v2/src/model/mods/generated_mods.rs deleted file mode 100644 index c72c215..0000000 --- a/rosu-v2/src/model/mods/generated_mods.rs +++ /dev/null @@ -1,12180 +0,0 @@ -//! This file was generated automatically. Do not modify. -//! -//! See - -use std::{ - borrow::Borrow, - cmp::Ordering, - fmt::{Display, Formatter, Result as FmtResult}, - num::NonZeroU8, -}; - -use crate::model::{ - mods::{Acronym, ModeAsSeed}, - GameMode, -}; -use serde::{ - de::{ - value::MapAccessDeserializer, DeserializeSeed, Deserializer, Error as DeError, IgnoredAny, - MapAccess, Visitor, - }, - Deserialize, -}; -use serde_json::value::RawValue; -/// Larger circles, more forgiving HP drain, less accuracy required, and three lives! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct EasyOsu { - pub retries: Option, -} -impl EasyOsu { - /// The acronym of [`EasyOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("EZ") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`EasyOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HR"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("DA"), - ] - } - .into_iter() - } - /// The description of [`EasyOsu`] - pub const fn description() -> &'static str { - "Larger circles, more forgiving HP drain, less accuracy required, and three lives!" - } - /// The [`GameModKind`] of [`EasyOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`EasyOsu`] - /// - /// See - pub const fn bits() -> u32 { - 2 - } -} -impl<'de> Deserialize<'de> for EasyOsu { - fn deserialize>(d: D) -> Result { - struct EasyOsuVisitor; - impl<'de> Visitor<'de> for EasyOsuVisitor { - type Value = EasyOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("EasyOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut retries = None; - while let Some(key) = map.next_key()? { - match key { - "retries" => retries = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - retries: retries.unwrap_or_default(), - }) - } - } - d.deserialize_map(EasyOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for EasyOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.retries.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.retries { - map.serialize_entry("retries", x)?; - } - map.end() - } -} -/// You can't fail, no matter what. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct NoFailOsu {} -impl NoFailOsu { - /// The acronym of [`NoFailOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NoFailOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`NoFailOsu`] - pub const fn description() -> &'static str { - "You can't fail, no matter what." - } - /// The [`GameModKind`] of [`NoFailOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`NoFailOsu`] - /// - /// See - pub const fn bits() -> u32 { - 1 - } -} -impl<'de> Deserialize<'de> for NoFailOsu { - fn deserialize>(d: D) -> Result { - struct NoFailOsuVisitor; - impl<'de> Visitor<'de> for NoFailOsuVisitor { - type Value = NoFailOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NoFailOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(NoFailOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NoFailOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Less zoom... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct HalfTimeOsu { - pub speed_change: Option, - pub adjust_pitch: Option, -} -impl HalfTimeOsu { - /// The acronym of [`HalfTimeOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HalfTimeOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`HalfTimeOsu`] - pub const fn description() -> &'static str { - "Less zoom..." - } - /// The [`GameModKind`] of [`HalfTimeOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`HalfTimeOsu`] - /// - /// See - pub const fn bits() -> u32 { - 256 - } -} -impl<'de> Deserialize<'de> for HalfTimeOsu { - fn deserialize>(d: D) -> Result { - struct HalfTimeOsuVisitor; - impl<'de> Visitor<'de> for HalfTimeOsuVisitor { - type Value = HalfTimeOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HalfTimeOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(HalfTimeOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HalfTimeOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.speed_change.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Whoaaaaa... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DaycoreOsu { - pub speed_change: Option, -} -impl DaycoreOsu { - /// The acronym of [`DaycoreOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DaycoreOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`DaycoreOsu`] - pub const fn description() -> &'static str { - "Whoaaaaa..." - } - /// The [`GameModKind`] of [`DaycoreOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } -} -impl<'de> Deserialize<'de> for DaycoreOsu { - fn deserialize>(d: D) -> Result { - struct DaycoreOsuVisitor; - impl<'de> Visitor<'de> for DaycoreOsuVisitor { - type Value = DaycoreOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DaycoreOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - }) - } - } - d.deserialize_map(DaycoreOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DaycoreOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.speed_change.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - map.end() - } -} -/// Everything just got a bit harder... -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct HardRockOsu {} -impl HardRockOsu { - /// The acronym of [`HardRockOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HardRockOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("DA"), - Acronym::from_str_unchecked("MR"), - ] - } - .into_iter() - } - /// The description of [`HardRockOsu`] - pub const fn description() -> &'static str { - "Everything just got a bit harder..." - } - /// The [`GameModKind`] of [`HardRockOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`HardRockOsu`] - /// - /// See - pub const fn bits() -> u32 { - 16 - } -} -impl<'de> Deserialize<'de> for HardRockOsu { - fn deserialize>(d: D) -> Result { - struct HardRockOsuVisitor; - impl<'de> Visitor<'de> for HardRockOsuVisitor { - type Value = HardRockOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HardRockOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(HardRockOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HardRockOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Miss and fail. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct SuddenDeathOsu { - pub restart: Option, -} -impl SuddenDeathOsu { - /// The acronym of [`SuddenDeathOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SuddenDeathOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("TP"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`SuddenDeathOsu`] - pub const fn description() -> &'static str { - "Miss and fail." - } - /// The [`GameModKind`] of [`SuddenDeathOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`SuddenDeathOsu`] - /// - /// See - pub const fn bits() -> u32 { - 32 - } -} -impl<'de> Deserialize<'de> for SuddenDeathOsu { - fn deserialize>(d: D) -> Result { - struct SuddenDeathOsuVisitor; - impl<'de> Visitor<'de> for SuddenDeathOsuVisitor { - type Value = SuddenDeathOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SuddenDeathOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(SuddenDeathOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SuddenDeathOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// SS or quit. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct PerfectOsu { - pub restart: Option, -} -impl PerfectOsu { - /// The acronym of [`PerfectOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("PF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`PerfectOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`PerfectOsu`] - pub const fn description() -> &'static str { - "SS or quit." - } - /// The [`GameModKind`] of [`PerfectOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`PerfectOsu`] - /// - /// See - pub const fn bits() -> u32 { - 16416 - } -} -impl<'de> Deserialize<'de> for PerfectOsu { - fn deserialize>(d: D) -> Result { - struct PerfectOsuVisitor; - impl<'de> Visitor<'de> for PerfectOsuVisitor { - type Value = PerfectOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("PerfectOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(PerfectOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for PerfectOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// Zoooooooooom... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DoubleTimeOsu { - pub speed_change: Option, - pub adjust_pitch: Option, -} -impl DoubleTimeOsu { - /// The acronym of [`DoubleTimeOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DoubleTimeOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`DoubleTimeOsu`] - pub const fn description() -> &'static str { - "Zoooooooooom..." - } - /// The [`GameModKind`] of [`DoubleTimeOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`DoubleTimeOsu`] - /// - /// See - pub const fn bits() -> u32 { - 64 - } -} -impl<'de> Deserialize<'de> for DoubleTimeOsu { - fn deserialize>(d: D) -> Result { - struct DoubleTimeOsuVisitor; - impl<'de> Visitor<'de> for DoubleTimeOsuVisitor { - type Value = DoubleTimeOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DoubleTimeOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(DoubleTimeOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DoubleTimeOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.speed_change.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Uguuuuuuuu... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct NightcoreOsu { - pub speed_change: Option, -} -impl NightcoreOsu { - /// The acronym of [`NightcoreOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NightcoreOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`NightcoreOsu`] - pub const fn description() -> &'static str { - "Uguuuuuuuu..." - } - /// The [`GameModKind`] of [`NightcoreOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`NightcoreOsu`] - /// - /// See - pub const fn bits() -> u32 { - 576 - } -} -impl<'de> Deserialize<'de> for NightcoreOsu { - fn deserialize>(d: D) -> Result { - struct NightcoreOsuVisitor; - impl<'de> Visitor<'de> for NightcoreOsuVisitor { - type Value = NightcoreOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NightcoreOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - }) - } - } - d.deserialize_map(NightcoreOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NightcoreOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.speed_change.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - map.end() - } -} -/// Play with no approach circles and fading circles/sliders. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct HiddenOsu { - pub only_fade_approach_circles: Option, -} -impl HiddenOsu { - /// The acronym of [`HiddenOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HiddenOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SI"), - Acronym::from_str_unchecked("TC"), - Acronym::from_str_unchecked("AD"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`HiddenOsu`] - pub const fn description() -> &'static str { - "Play with no approach circles and fading circles/sliders." - } - /// The [`GameModKind`] of [`HiddenOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`HiddenOsu`] - /// - /// See - pub const fn bits() -> u32 { - 8 - } -} -impl<'de> Deserialize<'de> for HiddenOsu { - fn deserialize>(d: D) -> Result { - struct HiddenOsuVisitor; - impl<'de> Visitor<'de> for HiddenOsuVisitor { - type Value = HiddenOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HiddenOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut only_fade_approach_circles = None; - while let Some(key) = map.next_key()? { - match key { - "only_fade_approach_circles" => { - only_fade_approach_circles = Some(map.next_value()?) - } - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - only_fade_approach_circles: only_fade_approach_circles.unwrap_or_default(), - }) - } - } - d.deserialize_map(HiddenOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HiddenOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.only_fade_approach_circles.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.only_fade_approach_circles { - map.serialize_entry("only_fade_approach_circles", x)?; - } - map.end() - } -} -/// Restricted view area. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct FlashlightOsu { - pub follow_delay: Option, - pub size_multiplier: Option, - pub combo_based_size: Option, -} -impl FlashlightOsu { - /// The acronym of [`FlashlightOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("FL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`FlashlightOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("BL")] }.into_iter() - } - /// The description of [`FlashlightOsu`] - pub const fn description() -> &'static str { - "Restricted view area." - } - /// The [`GameModKind`] of [`FlashlightOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`FlashlightOsu`] - /// - /// See - pub const fn bits() -> u32 { - 1024 - } -} -impl<'de> Deserialize<'de> for FlashlightOsu { - fn deserialize>(d: D) -> Result { - struct FlashlightOsuVisitor; - impl<'de> Visitor<'de> for FlashlightOsuVisitor { - type Value = FlashlightOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("FlashlightOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut follow_delay = None; - let mut size_multiplier = None; - let mut combo_based_size = None; - while let Some(key) = map.next_key()? { - match key { - "follow_delay" => follow_delay = Some(map.next_value()?), - "size_multiplier" => size_multiplier = Some(map.next_value()?), - "combo_based_size" => combo_based_size = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - follow_delay: follow_delay.unwrap_or_default(), - size_multiplier: size_multiplier.unwrap_or_default(), - combo_based_size: combo_based_size.unwrap_or_default(), - }) - } - } - d.deserialize_map(FlashlightOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for FlashlightOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.follow_delay.is_some() as usize - + self.size_multiplier.is_some() as usize - + self.combo_based_size.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.follow_delay { - map.serialize_entry("follow_delay", x)?; - } - if let Some(ref x) = self.size_multiplier { - map.serialize_entry("size_multiplier", x)?; - } - if let Some(ref x) = self.combo_based_size { - map.serialize_entry("combo_based_size", x)?; - } - map.end() - } -} -/// Play with blinds on your screen. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct BlindsOsu {} -impl BlindsOsu { - /// The acronym of [`BlindsOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("BL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`BlindsOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("FL")] }.into_iter() - } - /// The description of [`BlindsOsu`] - pub const fn description() -> &'static str { - "Play with blinds on your screen." - } - /// The [`GameModKind`] of [`BlindsOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } -} -impl<'de> Deserialize<'de> for BlindsOsu { - fn deserialize>(d: D) -> Result { - struct BlindsOsuVisitor; - impl<'de> Visitor<'de> for BlindsOsuVisitor { - type Value = BlindsOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("BlindsOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(BlindsOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for BlindsOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Once you start a slider, follow precisely or get a miss. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct StrictTrackingOsu {} -impl StrictTrackingOsu { - /// The acronym of [`StrictTrackingOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("ST") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`StrictTrackingOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("TP"), - Acronym::from_str_unchecked("CL"), - ] - } - .into_iter() - } - /// The description of [`StrictTrackingOsu`] - pub const fn description() -> &'static str { - "Once you start a slider, follow precisely or get a miss." - } - /// The [`GameModKind`] of [`StrictTrackingOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } -} -impl<'de> Deserialize<'de> for StrictTrackingOsu { - fn deserialize>(d: D) -> Result { - struct StrictTrackingOsuVisitor; - impl<'de> Visitor<'de> for StrictTrackingOsuVisitor { - type Value = StrictTrackingOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("StrictTrackingOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(StrictTrackingOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for StrictTrackingOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Fail if your accuracy drops too low! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct AccuracyChallengeOsu { - pub minimum_accuracy: Option, - pub accuracy_judge_mode: Option, - pub restart: Option, -} -impl AccuracyChallengeOsu { - /// The acronym of [`AccuracyChallengeOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AccuracyChallengeOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`AccuracyChallengeOsu`] - pub const fn description() -> &'static str { - "Fail if your accuracy drops too low!" - } - /// The [`GameModKind`] of [`AccuracyChallengeOsu`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } -} -impl<'de> Deserialize<'de> for AccuracyChallengeOsu { - fn deserialize>(d: D) -> Result { - struct AccuracyChallengeOsuVisitor; - impl<'de> Visitor<'de> for AccuracyChallengeOsuVisitor { - type Value = AccuracyChallengeOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AccuracyChallengeOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut minimum_accuracy = None; - let mut accuracy_judge_mode = None; - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "minimum_accuracy" => minimum_accuracy = Some(map.next_value()?), - "accuracy_judge_mode" => accuracy_judge_mode = Some(map.next_value()?), - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - minimum_accuracy: minimum_accuracy.unwrap_or_default(), - accuracy_judge_mode: accuracy_judge_mode.unwrap_or_default(), - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(AccuracyChallengeOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AccuracyChallengeOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.minimum_accuracy.is_some() as usize - + self.accuracy_judge_mode.is_some() as usize - + self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.minimum_accuracy { - map.serialize_entry("minimum_accuracy", x)?; - } - if let Some(ref x) = self.accuracy_judge_mode { - map.serialize_entry("accuracy_judge_mode", x)?; - } - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// Practice keeping up with the beat of the song. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct TargetPracticeOsu { - pub seed: Option, - pub metronome: Option, -} -impl TargetPracticeOsu { - /// The acronym of [`TargetPracticeOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("TP") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`TargetPracticeOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("ST"), - Acronym::from_str_unchecked("RD"), - Acronym::from_str_unchecked("SO"), - Acronym::from_str_unchecked("TC"), - Acronym::from_str_unchecked("AD"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`TargetPracticeOsu`] - pub const fn description() -> &'static str { - "Practice keeping up with the beat of the song." - } - /// The [`GameModKind`] of [`TargetPracticeOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`TargetPracticeOsu`] - /// - /// See - pub const fn bits() -> u32 { - 8388608 - } -} -impl<'de> Deserialize<'de> for TargetPracticeOsu { - fn deserialize>(d: D) -> Result { - struct TargetPracticeOsuVisitor; - impl<'de> Visitor<'de> for TargetPracticeOsuVisitor { - type Value = TargetPracticeOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("TargetPracticeOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut seed = None; - let mut metronome = None; - while let Some(key) = map.next_key()? { - match key { - "seed" => seed = Some(map.next_value()?), - "metronome" => metronome = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - seed: seed.unwrap_or_default(), - metronome: metronome.unwrap_or_default(), - }) - } - } - d.deserialize_map(TargetPracticeOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for TargetPracticeOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.seed.is_some() as usize + self.metronome.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.seed { - map.serialize_entry("seed", x)?; - } - if let Some(ref x) = self.metronome { - map.serialize_entry("metronome", x)?; - } - map.end() - } -} -/// Override a beatmap's difficulty settings. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DifficultyAdjustOsu { - pub circle_size: Option, - pub approach_rate: Option, - pub drain_rate: Option, - pub overall_difficulty: Option, - pub extended_limits: Option, -} -impl DifficultyAdjustOsu { - /// The acronym of [`DifficultyAdjustOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DA") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DifficultyAdjustOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("HR"), - ] - } - .into_iter() - } - /// The description of [`DifficultyAdjustOsu`] - pub const fn description() -> &'static str { - "Override a beatmap's difficulty settings." - } - /// The [`GameModKind`] of [`DifficultyAdjustOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for DifficultyAdjustOsu { - fn deserialize>(d: D) -> Result { - struct DifficultyAdjustOsuVisitor; - impl<'de> Visitor<'de> for DifficultyAdjustOsuVisitor { - type Value = DifficultyAdjustOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DifficultyAdjustOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut circle_size = None; - let mut approach_rate = None; - let mut drain_rate = None; - let mut overall_difficulty = None; - let mut extended_limits = None; - while let Some(key) = map.next_key()? { - match key { - "circle_size" => circle_size = Some(map.next_value()?), - "approach_rate" => approach_rate = Some(map.next_value()?), - "drain_rate" => drain_rate = Some(map.next_value()?), - "overall_difficulty" => overall_difficulty = Some(map.next_value()?), - "extended_limits" => extended_limits = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - circle_size: circle_size.unwrap_or_default(), - approach_rate: approach_rate.unwrap_or_default(), - drain_rate: drain_rate.unwrap_or_default(), - overall_difficulty: overall_difficulty.unwrap_or_default(), - extended_limits: extended_limits.unwrap_or_default(), - }) - } - } - d.deserialize_map(DifficultyAdjustOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DifficultyAdjustOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.circle_size.is_some() as usize - + self.approach_rate.is_some() as usize - + self.drain_rate.is_some() as usize - + self.overall_difficulty.is_some() as usize - + self.extended_limits.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.circle_size { - map.serialize_entry("circle_size", x)?; - } - if let Some(ref x) = self.approach_rate { - map.serialize_entry("approach_rate", x)?; - } - if let Some(ref x) = self.drain_rate { - map.serialize_entry("drain_rate", x)?; - } - if let Some(ref x) = self.overall_difficulty { - map.serialize_entry("overall_difficulty", x)?; - } - if let Some(ref x) = self.extended_limits { - map.serialize_entry("extended_limits", x)?; - } - map.end() - } -} -/// Feeling nostalgic? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct ClassicOsu { - pub no_slider_head_accuracy: Option, - pub classic_note_lock: Option, - pub always_play_tail_sample: Option, - pub fade_hit_circle_early: Option, - pub classic_health: Option, -} -impl ClassicOsu { - /// The acronym of [`ClassicOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ClassicOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("ST")] }.into_iter() - } - /// The description of [`ClassicOsu`] - pub const fn description() -> &'static str { - "Feeling nostalgic?" - } - /// The [`GameModKind`] of [`ClassicOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for ClassicOsu { - fn deserialize>(d: D) -> Result { - struct ClassicOsuVisitor; - impl<'de> Visitor<'de> for ClassicOsuVisitor { - type Value = ClassicOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ClassicOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut no_slider_head_accuracy = None; - let mut classic_note_lock = None; - let mut always_play_tail_sample = None; - let mut fade_hit_circle_early = None; - let mut classic_health = None; - while let Some(key) = map.next_key()? { - match key { - "no_slider_head_accuracy" => { - no_slider_head_accuracy = Some(map.next_value()?) - } - "classic_note_lock" => classic_note_lock = Some(map.next_value()?), - "always_play_tail_sample" => { - always_play_tail_sample = Some(map.next_value()?) - } - "fade_hit_circle_early" => fade_hit_circle_early = Some(map.next_value()?), - "classic_health" => classic_health = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - no_slider_head_accuracy: no_slider_head_accuracy.unwrap_or_default(), - classic_note_lock: classic_note_lock.unwrap_or_default(), - always_play_tail_sample: always_play_tail_sample.unwrap_or_default(), - fade_hit_circle_early: fade_hit_circle_early.unwrap_or_default(), - classic_health: classic_health.unwrap_or_default(), - }) - } - } - d.deserialize_map(ClassicOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ClassicOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.no_slider_head_accuracy.is_some() as usize - + self.classic_note_lock.is_some() as usize - + self.always_play_tail_sample.is_some() as usize - + self.fade_hit_circle_early.is_some() as usize - + self.classic_health.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.no_slider_head_accuracy { - map.serialize_entry("no_slider_head_accuracy", x)?; - } - if let Some(ref x) = self.classic_note_lock { - map.serialize_entry("classic_note_lock", x)?; - } - if let Some(ref x) = self.always_play_tail_sample { - map.serialize_entry("always_play_tail_sample", x)?; - } - if let Some(ref x) = self.fade_hit_circle_early { - map.serialize_entry("fade_hit_circle_early", x)?; - } - if let Some(ref x) = self.classic_health { - map.serialize_entry("classic_health", x)?; - } - map.end() - } -} -/// It never gets boring! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct RandomOsu { - pub angle_sharpness: Option, - pub seed: Option, -} -impl RandomOsu { - /// The acronym of [`RandomOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("RD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`RandomOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("TP")] }.into_iter() - } - /// The description of [`RandomOsu`] - pub const fn description() -> &'static str { - "It never gets boring!" - } - /// The [`GameModKind`] of [`RandomOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`RandomOsu`] - /// - /// See - pub const fn bits() -> u32 { - 2097152 - } -} -impl<'de> Deserialize<'de> for RandomOsu { - fn deserialize>(d: D) -> Result { - struct RandomOsuVisitor; - impl<'de> Visitor<'de> for RandomOsuVisitor { - type Value = RandomOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("RandomOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut angle_sharpness = None; - let mut seed = None; - while let Some(key) = map.next_key()? { - match key { - "angle_sharpness" => angle_sharpness = Some(map.next_value()?), - "seed" => seed = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - angle_sharpness: angle_sharpness.unwrap_or_default(), - seed: seed.unwrap_or_default(), - }) - } - } - d.deserialize_map(RandomOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for RandomOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.angle_sharpness.is_some() as usize + self.seed.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.angle_sharpness { - map.serialize_entry("angle_sharpness", x)?; - } - if let Some(ref x) = self.seed { - map.serialize_entry("seed", x)?; - } - map.end() - } -} -/// Flip objects on the chosen axes. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct MirrorOsu { - pub reflection: Option, -} -impl MirrorOsu { - /// The acronym of [`MirrorOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("MR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`MirrorOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("HR")] }.into_iter() - } - /// The description of [`MirrorOsu`] - pub const fn description() -> &'static str { - "Flip objects on the chosen axes." - } - /// The [`GameModKind`] of [`MirrorOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`MirrorOsu`] - /// - /// See - pub const fn bits() -> u32 { - 1073741824 - } -} -impl<'de> Deserialize<'de> for MirrorOsu { - fn deserialize>(d: D) -> Result { - struct MirrorOsuVisitor; - impl<'de> Visitor<'de> for MirrorOsuVisitor { - type Value = MirrorOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("MirrorOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut reflection = None; - while let Some(key) = map.next_key()? { - match key { - "reflection" => reflection = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - reflection: reflection.unwrap_or_default(), - }) - } - } - d.deserialize_map(MirrorOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for MirrorOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.reflection.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.reflection { - map.serialize_entry("reflection", x)?; - } - map.end() - } -} -/// Don't use the same key twice in a row! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct AlternateOsu {} -impl AlternateOsu { - /// The acronym of [`AlternateOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AlternateOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SG"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("RX"), - ] - } - .into_iter() - } - /// The description of [`AlternateOsu`] - pub const fn description() -> &'static str { - "Don't use the same key twice in a row!" - } - /// The [`GameModKind`] of [`AlternateOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for AlternateOsu { - fn deserialize>(d: D) -> Result { - struct AlternateOsuVisitor; - impl<'de> Visitor<'de> for AlternateOsuVisitor { - type Value = AlternateOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AlternateOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(AlternateOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AlternateOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// You must only use one key! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct SingleTapOsu {} -impl SingleTapOsu { - /// The acronym of [`SingleTapOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SG") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SingleTapOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("AL"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("RX"), - ] - } - .into_iter() - } - /// The description of [`SingleTapOsu`] - pub const fn description() -> &'static str { - "You must only use one key!" - } - /// The [`GameModKind`] of [`SingleTapOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for SingleTapOsu { - fn deserialize>(d: D) -> Result { - struct SingleTapOsuVisitor; - impl<'de> Visitor<'de> for SingleTapOsuVisitor { - type Value = SingleTapOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SingleTapOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(SingleTapOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SingleTapOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Watch a perfect automated play through the song. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct AutoplayOsu {} -impl AutoplayOsu { - /// The acronym of [`AutoplayOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AutoplayOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("AL"), - Acronym::from_str_unchecked("SG"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("RX"), - Acronym::from_str_unchecked("AP"), - Acronym::from_str_unchecked("SO"), - Acronym::from_str_unchecked("MG"), - Acronym::from_str_unchecked("RP"), - Acronym::from_str_unchecked("AS"), - Acronym::from_str_unchecked("TD"), - ] - } - .into_iter() - } - /// The description of [`AutoplayOsu`] - pub const fn description() -> &'static str { - "Watch a perfect automated play through the song." - } - /// The [`GameModKind`] of [`AutoplayOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`AutoplayOsu`] - /// - /// See - pub const fn bits() -> u32 { - 2048 - } -} -impl<'de> Deserialize<'de> for AutoplayOsu { - fn deserialize>(d: D) -> Result { - struct AutoplayOsuVisitor; - impl<'de> Visitor<'de> for AutoplayOsuVisitor { - type Value = AutoplayOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AutoplayOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(AutoplayOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AutoplayOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Watch the video without visual distractions. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct CinemaOsu {} -impl CinemaOsu { - /// The acronym of [`CinemaOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CN") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`CinemaOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("AL"), - Acronym::from_str_unchecked("SG"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("RX"), - Acronym::from_str_unchecked("AP"), - Acronym::from_str_unchecked("SO"), - Acronym::from_str_unchecked("MG"), - Acronym::from_str_unchecked("RP"), - Acronym::from_str_unchecked("AS"), - Acronym::from_str_unchecked("TD"), - ] - } - .into_iter() - } - /// The description of [`CinemaOsu`] - pub const fn description() -> &'static str { - "Watch the video without visual distractions." - } - /// The [`GameModKind`] of [`CinemaOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`CinemaOsu`] - /// - /// See - pub const fn bits() -> u32 { - 4194304 - } -} -impl<'de> Deserialize<'de> for CinemaOsu { - fn deserialize>(d: D) -> Result { - struct CinemaOsuVisitor; - impl<'de> Visitor<'de> for CinemaOsuVisitor { - type Value = CinemaOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("CinemaOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(CinemaOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for CinemaOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// You don't need to click. Give your clicking/tapping fingers a break from the heat of things. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct RelaxOsu {} -impl RelaxOsu { - /// The acronym of [`RelaxOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("RX") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`RelaxOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("AL"), - Acronym::from_str_unchecked("SG"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("AP"), - Acronym::from_str_unchecked("MG"), - ] - } - .into_iter() - } - /// The description of [`RelaxOsu`] - pub const fn description() -> &'static str { - "You don't need to click. Give your clicking/tapping fingers a break from the heat of things." - } - /// The [`GameModKind`] of [`RelaxOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`RelaxOsu`] - /// - /// See - pub const fn bits() -> u32 { - 128 - } -} -impl<'de> Deserialize<'de> for RelaxOsu { - fn deserialize>(d: D) -> Result { - struct RelaxOsuVisitor; - impl<'de> Visitor<'de> for RelaxOsuVisitor { - type Value = RelaxOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("RelaxOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(RelaxOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for RelaxOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Automatic cursor movement - just follow the rhythm. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct AutopilotOsu {} -impl AutopilotOsu { - /// The acronym of [`AutopilotOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AP") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AutopilotOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("RX"), - Acronym::from_str_unchecked("SO"), - Acronym::from_str_unchecked("MG"), - Acronym::from_str_unchecked("RP"), - Acronym::from_str_unchecked("TD"), - ] - } - .into_iter() - } - /// The description of [`AutopilotOsu`] - pub const fn description() -> &'static str { - "Automatic cursor movement - just follow the rhythm." - } - /// The [`GameModKind`] of [`AutopilotOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`AutopilotOsu`] - /// - /// See - pub const fn bits() -> u32 { - 8192 - } -} -impl<'de> Deserialize<'de> for AutopilotOsu { - fn deserialize>(d: D) -> Result { - struct AutopilotOsuVisitor; - impl<'de> Visitor<'de> for AutopilotOsuVisitor { - type Value = AutopilotOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AutopilotOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(AutopilotOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AutopilotOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Spinners will be automatically completed. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct SpunOutOsu {} -impl SpunOutOsu { - /// The acronym of [`SpunOutOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SO") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SpunOutOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("TP"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("AP"), - ] - } - .into_iter() - } - /// The description of [`SpunOutOsu`] - pub const fn description() -> &'static str { - "Spinners will be automatically completed." - } - /// The [`GameModKind`] of [`SpunOutOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`SpunOutOsu`] - /// - /// See - pub const fn bits() -> u32 { - 4096 - } -} -impl<'de> Deserialize<'de> for SpunOutOsu { - fn deserialize>(d: D) -> Result { - struct SpunOutOsuVisitor; - impl<'de> Visitor<'de> for SpunOutOsuVisitor { - type Value = SpunOutOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SpunOutOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(SpunOutOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SpunOutOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Everything rotates. EVERYTHING. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct TransformOsu {} -impl TransformOsu { - /// The acronym of [`TransformOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("TR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`TransformOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("WG"), - Acronym::from_str_unchecked("MG"), - Acronym::from_str_unchecked("RP"), - Acronym::from_str_unchecked("FR"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`TransformOsu`] - pub const fn description() -> &'static str { - "Everything rotates. EVERYTHING." - } - /// The [`GameModKind`] of [`TransformOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for TransformOsu { - fn deserialize>(d: D) -> Result { - struct TransformOsuVisitor; - impl<'de> Visitor<'de> for TransformOsuVisitor { - type Value = TransformOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("TransformOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(TransformOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for TransformOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// They just won't stay still... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct WiggleOsu { - pub strength: Option, -} -impl WiggleOsu { - /// The acronym of [`WiggleOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("WG") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`WiggleOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("TR"), - Acronym::from_str_unchecked("MG"), - Acronym::from_str_unchecked("RP"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`WiggleOsu`] - pub const fn description() -> &'static str { - "They just won't stay still..." - } - /// The [`GameModKind`] of [`WiggleOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for WiggleOsu { - fn deserialize>(d: D) -> Result { - struct WiggleOsuVisitor; - impl<'de> Visitor<'de> for WiggleOsuVisitor { - type Value = WiggleOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("WiggleOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut strength = None; - while let Some(key) = map.next_key()? { - match key { - "strength" => strength = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - strength: strength.unwrap_or_default(), - }) - } - } - d.deserialize_map(WiggleOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for WiggleOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.strength.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.strength { - map.serialize_entry("strength", x)?; - } - map.end() - } -} -/// Circles spin in. No approach circles. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct SpinInOsu {} -impl SpinInOsu { - /// The acronym of [`SpinInOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SI") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SpinInOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HD"), - Acronym::from_str_unchecked("GR"), - Acronym::from_str_unchecked("DF"), - Acronym::from_str_unchecked("TC"), - Acronym::from_str_unchecked("AD"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`SpinInOsu`] - pub const fn description() -> &'static str { - "Circles spin in. No approach circles." - } - /// The [`GameModKind`] of [`SpinInOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for SpinInOsu { - fn deserialize>(d: D) -> Result { - struct SpinInOsuVisitor; - impl<'de> Visitor<'de> for SpinInOsuVisitor { - type Value = SpinInOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SpinInOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(SpinInOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SpinInOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Hit them at the right size! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct GrowOsu { - pub start_scale: Option, -} -impl GrowOsu { - /// The acronym of [`GrowOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("GR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`GrowOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SI"), - Acronym::from_str_unchecked("DF"), - Acronym::from_str_unchecked("TC"), - Acronym::from_str_unchecked("AD"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`GrowOsu`] - pub const fn description() -> &'static str { - "Hit them at the right size!" - } - /// The [`GameModKind`] of [`GrowOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for GrowOsu { - fn deserialize>(d: D) -> Result { - struct GrowOsuVisitor; - impl<'de> Visitor<'de> for GrowOsuVisitor { - type Value = GrowOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("GrowOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut start_scale = None; - while let Some(key) = map.next_key()? { - match key { - "start_scale" => start_scale = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - start_scale: start_scale.unwrap_or_default(), - }) - } - } - d.deserialize_map(GrowOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for GrowOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.start_scale.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.start_scale { - map.serialize_entry("start_scale", x)?; - } - map.end() - } -} -/// Hit them at the right size! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DeflateOsu { - pub start_scale: Option, -} -impl DeflateOsu { - /// The acronym of [`DeflateOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DeflateOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SI"), - Acronym::from_str_unchecked("GR"), - Acronym::from_str_unchecked("TC"), - Acronym::from_str_unchecked("AD"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`DeflateOsu`] - pub const fn description() -> &'static str { - "Hit them at the right size!" - } - /// The [`GameModKind`] of [`DeflateOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for DeflateOsu { - fn deserialize>(d: D) -> Result { - struct DeflateOsuVisitor; - impl<'de> Visitor<'de> for DeflateOsuVisitor { - type Value = DeflateOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DeflateOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut start_scale = None; - while let Some(key) = map.next_key()? { - match key { - "start_scale" => start_scale = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - start_scale: start_scale.unwrap_or_default(), - }) - } - } - d.deserialize_map(DeflateOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DeflateOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.start_scale.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.start_scale { - map.serialize_entry("start_scale", x)?; - } - map.end() - } -} -/// Can you keep up? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct WindUpOsu { - pub initial_rate: Option, - pub final_rate: Option, - pub adjust_pitch: Option, -} -impl WindUpOsu { - /// The acronym of [`WindUpOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("WU") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`WindUpOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`WindUpOsu`] - pub const fn description() -> &'static str { - "Can you keep up?" - } - /// The [`GameModKind`] of [`WindUpOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for WindUpOsu { - fn deserialize>(d: D) -> Result { - struct WindUpOsuVisitor; - impl<'de> Visitor<'de> for WindUpOsuVisitor { - type Value = WindUpOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("WindUpOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut final_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "final_rate" => final_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - final_rate: final_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(WindUpOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for WindUpOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.initial_rate.is_some() as usize - + self.final_rate.is_some() as usize - + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.final_rate { - map.serialize_entry("final_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Sloooow doooown... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct WindDownOsu { - pub initial_rate: Option, - pub final_rate: Option, - pub adjust_pitch: Option, -} -impl WindDownOsu { - /// The acronym of [`WindDownOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("WD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`WindDownOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`WindDownOsu`] - pub const fn description() -> &'static str { - "Sloooow doooown..." - } - /// The [`GameModKind`] of [`WindDownOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for WindDownOsu { - fn deserialize>(d: D) -> Result { - struct WindDownOsuVisitor; - impl<'de> Visitor<'de> for WindDownOsuVisitor { - type Value = WindDownOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("WindDownOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut final_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "final_rate" => final_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - final_rate: final_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(WindDownOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for WindDownOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.initial_rate.is_some() as usize - + self.final_rate.is_some() as usize - + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.final_rate { - map.serialize_entry("final_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Put your faith in the approach circles... -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct TraceableOsu {} -impl TraceableOsu { - /// The acronym of [`TraceableOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("TC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`TraceableOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HD"), - Acronym::from_str_unchecked("TP"), - Acronym::from_str_unchecked("SI"), - Acronym::from_str_unchecked("GR"), - Acronym::from_str_unchecked("DF"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`TraceableOsu`] - pub const fn description() -> &'static str { - "Put your faith in the approach circles..." - } - /// The [`GameModKind`] of [`TraceableOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for TraceableOsu { - fn deserialize>(d: D) -> Result { - struct TraceableOsuVisitor; - impl<'de> Visitor<'de> for TraceableOsuVisitor { - type Value = TraceableOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("TraceableOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(TraceableOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for TraceableOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// The whole playfield is on a wheel! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct BarrelRollOsu { - pub spin_speed: Option, - pub direction: Option, -} -impl BarrelRollOsu { - /// The acronym of [`BarrelRollOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("BR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`BarrelRollOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("BU")] }.into_iter() - } - /// The description of [`BarrelRollOsu`] - pub const fn description() -> &'static str { - "The whole playfield is on a wheel!" - } - /// The [`GameModKind`] of [`BarrelRollOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for BarrelRollOsu { - fn deserialize>(d: D) -> Result { - struct BarrelRollOsuVisitor; - impl<'de> Visitor<'de> for BarrelRollOsuVisitor { - type Value = BarrelRollOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("BarrelRollOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut spin_speed = None; - let mut direction = None; - while let Some(key) = map.next_key()? { - match key { - "spin_speed" => spin_speed = Some(map.next_value()?), - "direction" => direction = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - spin_speed: spin_speed.unwrap_or_default(), - direction: direction.unwrap_or_default(), - }) - } - } - d.deserialize_map(BarrelRollOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for BarrelRollOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.spin_speed.is_some() as usize + self.direction.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.spin_speed { - map.serialize_entry("spin_speed", x)?; - } - if let Some(ref x) = self.direction { - map.serialize_entry("direction", x)?; - } - map.end() - } -} -/// Never trust the approach circles... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct ApproachDifferentOsu { - pub scale: Option, - pub style: Option, -} -impl ApproachDifferentOsu { - /// The acronym of [`ApproachDifferentOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ApproachDifferentOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HD"), - Acronym::from_str_unchecked("TP"), - Acronym::from_str_unchecked("SI"), - Acronym::from_str_unchecked("GR"), - Acronym::from_str_unchecked("DF"), - Acronym::from_str_unchecked("FR"), - ] - } - .into_iter() - } - /// The description of [`ApproachDifferentOsu`] - pub const fn description() -> &'static str { - "Never trust the approach circles..." - } - /// The [`GameModKind`] of [`ApproachDifferentOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for ApproachDifferentOsu { - fn deserialize>(d: D) -> Result { - struct ApproachDifferentOsuVisitor; - impl<'de> Visitor<'de> for ApproachDifferentOsuVisitor { - type Value = ApproachDifferentOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ApproachDifferentOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut scale = None; - let mut style = None; - while let Some(key) = map.next_key()? { - match key { - "scale" => scale = Some(map.next_value()?), - "style" => style = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - scale: scale.unwrap_or_default(), - style: style.unwrap_or_default(), - }) - } - } - d.deserialize_map(ApproachDifferentOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ApproachDifferentOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.scale.is_some() as usize + self.style.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.scale { - map.serialize_entry("scale", x)?; - } - if let Some(ref x) = self.style { - map.serialize_entry("style", x)?; - } - map.end() - } -} -/// Can you still feel the rhythm without music? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct MutedOsu { - pub inverse_muting: Option, - pub enable_metronome: Option, - pub mute_combo_count: Option, - pub affects_hit_sounds: Option, -} -impl MutedOsu { - /// The acronym of [`MutedOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("MU") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`MutedOsu`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`MutedOsu`] - pub const fn description() -> &'static str { - "Can you still feel the rhythm without music?" - } - /// The [`GameModKind`] of [`MutedOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for MutedOsu { - fn deserialize>(d: D) -> Result { - struct MutedOsuVisitor; - impl<'de> Visitor<'de> for MutedOsuVisitor { - type Value = MutedOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("MutedOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut inverse_muting = None; - let mut enable_metronome = None; - let mut mute_combo_count = None; - let mut affects_hit_sounds = None; - while let Some(key) = map.next_key()? { - match key { - "inverse_muting" => inverse_muting = Some(map.next_value()?), - "enable_metronome" => enable_metronome = Some(map.next_value()?), - "mute_combo_count" => mute_combo_count = Some(map.next_value()?), - "affects_hit_sounds" => affects_hit_sounds = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - inverse_muting: inverse_muting.unwrap_or_default(), - enable_metronome: enable_metronome.unwrap_or_default(), - mute_combo_count: mute_combo_count.unwrap_or_default(), - affects_hit_sounds: affects_hit_sounds.unwrap_or_default(), - }) - } - } - d.deserialize_map(MutedOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for MutedOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.inverse_muting.is_some() as usize - + self.enable_metronome.is_some() as usize - + self.mute_combo_count.is_some() as usize - + self.affects_hit_sounds.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.inverse_muting { - map.serialize_entry("inverse_muting", x)?; - } - if let Some(ref x) = self.enable_metronome { - map.serialize_entry("enable_metronome", x)?; - } - if let Some(ref x) = self.mute_combo_count { - map.serialize_entry("mute_combo_count", x)?; - } - if let Some(ref x) = self.affects_hit_sounds { - map.serialize_entry("affects_hit_sounds", x)?; - } - map.end() - } -} -/// Where's the cursor? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct NoScopeOsu { - pub hidden_combo_count: Option, -} -impl NoScopeOsu { - /// The acronym of [`NoScopeOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NS") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NoScopeOsu`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`NoScopeOsu`] - pub const fn description() -> &'static str { - "Where's the cursor?" - } - /// The [`GameModKind`] of [`NoScopeOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for NoScopeOsu { - fn deserialize>(d: D) -> Result { - struct NoScopeOsuVisitor; - impl<'de> Visitor<'de> for NoScopeOsuVisitor { - type Value = NoScopeOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NoScopeOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut hidden_combo_count = None; - while let Some(key) = map.next_key()? { - match key { - "hidden_combo_count" => hidden_combo_count = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - hidden_combo_count: hidden_combo_count.unwrap_or_default(), - }) - } - } - d.deserialize_map(NoScopeOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NoScopeOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.hidden_combo_count.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.hidden_combo_count { - map.serialize_entry("hidden_combo_count", x)?; - } - map.end() - } -} -/// No need to chase the circles – your cursor is a magnet! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct MagnetisedOsu { - pub attraction_strength: Option, -} -impl MagnetisedOsu { - /// The acronym of [`MagnetisedOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("MG") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`MagnetisedOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("RX"), - Acronym::from_str_unchecked("AP"), - Acronym::from_str_unchecked("TR"), - Acronym::from_str_unchecked("WG"), - Acronym::from_str_unchecked("RP"), - Acronym::from_str_unchecked("BU"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`MagnetisedOsu`] - pub const fn description() -> &'static str { - "No need to chase the circles – your cursor is a magnet!" - } - /// The [`GameModKind`] of [`MagnetisedOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for MagnetisedOsu { - fn deserialize>(d: D) -> Result { - struct MagnetisedOsuVisitor; - impl<'de> Visitor<'de> for MagnetisedOsuVisitor { - type Value = MagnetisedOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("MagnetisedOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut attraction_strength = None; - while let Some(key) = map.next_key()? { - match key { - "attraction_strength" => attraction_strength = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - attraction_strength: attraction_strength.unwrap_or_default(), - }) - } - } - d.deserialize_map(MagnetisedOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for MagnetisedOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.attraction_strength.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.attraction_strength { - map.serialize_entry("attraction_strength", x)?; - } - map.end() - } -} -/// Hit objects run away! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct RepelOsu { - pub repulsion_strength: Option, -} -impl RepelOsu { - /// The acronym of [`RepelOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("RP") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`RepelOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("AP"), - Acronym::from_str_unchecked("TR"), - Acronym::from_str_unchecked("WG"), - Acronym::from_str_unchecked("MG"), - Acronym::from_str_unchecked("BU"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`RepelOsu`] - pub const fn description() -> &'static str { - "Hit objects run away!" - } - /// The [`GameModKind`] of [`RepelOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for RepelOsu { - fn deserialize>(d: D) -> Result { - struct RepelOsuVisitor; - impl<'de> Visitor<'de> for RepelOsuVisitor { - type Value = RepelOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("RepelOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut repulsion_strength = None; - while let Some(key) = map.next_key()? { - match key { - "repulsion_strength" => repulsion_strength = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - repulsion_strength: repulsion_strength.unwrap_or_default(), - }) - } - } - d.deserialize_map(RepelOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for RepelOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.repulsion_strength.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.repulsion_strength { - map.serialize_entry("repulsion_strength", x)?; - } - map.end() - } -} -/// Let track speed adapt to you. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct AdaptiveSpeedOsu { - pub initial_rate: Option, - pub adjust_pitch: Option, -} -impl AdaptiveSpeedOsu { - /// The acronym of [`AdaptiveSpeedOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AS") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AdaptiveSpeedOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - ] - } - .into_iter() - } - /// The description of [`AdaptiveSpeedOsu`] - pub const fn description() -> &'static str { - "Let track speed adapt to you." - } - /// The [`GameModKind`] of [`AdaptiveSpeedOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for AdaptiveSpeedOsu { - fn deserialize>(d: D) -> Result { - struct AdaptiveSpeedOsuVisitor; - impl<'de> Visitor<'de> for AdaptiveSpeedOsuVisitor { - type Value = AdaptiveSpeedOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AdaptiveSpeedOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(AdaptiveSpeedOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AdaptiveSpeedOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.initial_rate.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Burn the notes into your memory. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct FreezeFrameOsu {} -impl FreezeFrameOsu { - /// The acronym of [`FreezeFrameOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("FR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`FreezeFrameOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("TR"), - Acronym::from_str_unchecked("AD"), - Acronym::from_str_unchecked("DP"), - ] - } - .into_iter() - } - /// The description of [`FreezeFrameOsu`] - pub const fn description() -> &'static str { - "Burn the notes into your memory." - } - /// The [`GameModKind`] of [`FreezeFrameOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for FreezeFrameOsu { - fn deserialize>(d: D) -> Result { - struct FreezeFrameOsuVisitor; - impl<'de> Visitor<'de> for FreezeFrameOsuVisitor { - type Value = FreezeFrameOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("FreezeFrameOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(FreezeFrameOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for FreezeFrameOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Don't let their popping distract you! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct BubblesOsu {} -impl BubblesOsu { - /// The acronym of [`BubblesOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("BU") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`BubblesOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("BR"), - Acronym::from_str_unchecked("MG"), - Acronym::from_str_unchecked("RP"), - ] - } - .into_iter() - } - /// The description of [`BubblesOsu`] - pub const fn description() -> &'static str { - "Don't let their popping distract you!" - } - /// The [`GameModKind`] of [`BubblesOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for BubblesOsu { - fn deserialize>(d: D) -> Result { - struct BubblesOsuVisitor; - impl<'de> Visitor<'de> for BubblesOsuVisitor { - type Value = BubblesOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("BubblesOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(BubblesOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for BubblesOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Colours hit objects based on the rhythm. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct SynesthesiaOsu {} -impl SynesthesiaOsu { - /// The acronym of [`SynesthesiaOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SY") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SynesthesiaOsu`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`SynesthesiaOsu`] - pub const fn description() -> &'static str { - "Colours hit objects based on the rhythm." - } - /// The [`GameModKind`] of [`SynesthesiaOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for SynesthesiaOsu { - fn deserialize>(d: D) -> Result { - struct SynesthesiaOsuVisitor; - impl<'de> Visitor<'de> for SynesthesiaOsuVisitor { - type Value = SynesthesiaOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SynesthesiaOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(SynesthesiaOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SynesthesiaOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// 3D. Almost. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DepthOsu { - pub max_depth: Option, - pub show_approach_circles: Option, -} -impl DepthOsu { - /// The acronym of [`DepthOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DP") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DepthOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HD"), - Acronym::from_str_unchecked("TP"), - Acronym::from_str_unchecked("TR"), - Acronym::from_str_unchecked("WG"), - Acronym::from_str_unchecked("SI"), - Acronym::from_str_unchecked("GR"), - Acronym::from_str_unchecked("DF"), - Acronym::from_str_unchecked("TC"), - Acronym::from_str_unchecked("MG"), - Acronym::from_str_unchecked("RP"), - Acronym::from_str_unchecked("FR"), - ] - } - .into_iter() - } - /// The description of [`DepthOsu`] - pub const fn description() -> &'static str { - "3D. Almost." - } - /// The [`GameModKind`] of [`DepthOsu`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for DepthOsu { - fn deserialize>(d: D) -> Result { - struct DepthOsuVisitor; - impl<'de> Visitor<'de> for DepthOsuVisitor { - type Value = DepthOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DepthOsu") - } - fn visit_map>(self, mut map: A) -> Result { - let mut max_depth = None; - let mut show_approach_circles = None; - while let Some(key) = map.next_key()? { - match key { - "max_depth" => max_depth = Some(map.next_value()?), - "show_approach_circles" => show_approach_circles = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - max_depth: max_depth.unwrap_or_default(), - show_approach_circles: show_approach_circles.unwrap_or_default(), - }) - } - } - d.deserialize_map(DepthOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DepthOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.max_depth.is_some() as usize + self.show_approach_circles.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.max_depth { - map.serialize_entry("max_depth", x)?; - } - if let Some(ref x) = self.show_approach_circles { - map.serialize_entry("show_approach_circles", x)?; - } - map.end() - } -} -/// Automatically applied to plays on devices with a touchscreen. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct TouchDeviceOsu {} -impl TouchDeviceOsu { - /// The acronym of [`TouchDeviceOsu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("TD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`TouchDeviceOsu`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("AP"), - ] - } - .into_iter() - } - /// The description of [`TouchDeviceOsu`] - pub const fn description() -> &'static str { - "Automatically applied to plays on devices with a touchscreen." - } - /// The [`GameModKind`] of [`TouchDeviceOsu`] - pub const fn kind() -> GameModKind { - GameModKind::System - } - /// Bit value of [`TouchDeviceOsu`] - /// - /// See - pub const fn bits() -> u32 { - 4 - } -} -impl<'de> Deserialize<'de> for TouchDeviceOsu { - fn deserialize>(d: D) -> Result { - struct TouchDeviceOsuVisitor; - impl<'de> Visitor<'de> for TouchDeviceOsuVisitor { - type Value = TouchDeviceOsu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("TouchDeviceOsu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(TouchDeviceOsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for TouchDeviceOsu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Score set on earlier osu! versions with the V2 scoring algorithm active. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ScoreV2Osu {} -impl ScoreV2Osu { - /// The acronym of [`ScoreV2Osu`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SV2") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ScoreV2Osu`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`ScoreV2Osu`] - pub const fn description() -> &'static str { - "Score set on earlier osu! versions with the V2 scoring algorithm active." - } - /// The [`GameModKind`] of [`ScoreV2Osu`] - pub const fn kind() -> GameModKind { - GameModKind::System - } - /// Bit value of [`ScoreV2Osu`] - /// - /// See - pub const fn bits() -> u32 { - 536870912 - } -} -impl<'de> Deserialize<'de> for ScoreV2Osu { - fn deserialize>(d: D) -> Result { - struct ScoreV2OsuVisitor; - impl<'de> Visitor<'de> for ScoreV2OsuVisitor { - type Value = ScoreV2Osu; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ScoreV2Osu") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ScoreV2OsuVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ScoreV2Osu { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Beats move slower, and less accuracy required! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct EasyTaiko {} -impl EasyTaiko { - /// The acronym of [`EasyTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("EZ") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`EasyTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HR"), - Acronym::from_str_unchecked("DA"), - ] - } - .into_iter() - } - /// The description of [`EasyTaiko`] - pub const fn description() -> &'static str { - "Beats move slower, and less accuracy required!" - } - /// The [`GameModKind`] of [`EasyTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`EasyTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 2 - } -} -impl<'de> Deserialize<'de> for EasyTaiko { - fn deserialize>(d: D) -> Result { - struct EasyTaikoVisitor; - impl<'de> Visitor<'de> for EasyTaikoVisitor { - type Value = EasyTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("EasyTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(EasyTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for EasyTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// You can't fail, no matter what. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct NoFailTaiko {} -impl NoFailTaiko { - /// The acronym of [`NoFailTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NoFailTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`NoFailTaiko`] - pub const fn description() -> &'static str { - "You can't fail, no matter what." - } - /// The [`GameModKind`] of [`NoFailTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`NoFailTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 1 - } -} -impl<'de> Deserialize<'de> for NoFailTaiko { - fn deserialize>(d: D) -> Result { - struct NoFailTaikoVisitor; - impl<'de> Visitor<'de> for NoFailTaikoVisitor { - type Value = NoFailTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NoFailTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(NoFailTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NoFailTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Less zoom... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct HalfTimeTaiko { - pub speed_change: Option, - pub adjust_pitch: Option, -} -impl HalfTimeTaiko { - /// The acronym of [`HalfTimeTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HalfTimeTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`HalfTimeTaiko`] - pub const fn description() -> &'static str { - "Less zoom..." - } - /// The [`GameModKind`] of [`HalfTimeTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`HalfTimeTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 256 - } -} -impl<'de> Deserialize<'de> for HalfTimeTaiko { - fn deserialize>(d: D) -> Result { - struct HalfTimeTaikoVisitor; - impl<'de> Visitor<'de> for HalfTimeTaikoVisitor { - type Value = HalfTimeTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HalfTimeTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(HalfTimeTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HalfTimeTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.speed_change.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Whoaaaaa... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DaycoreTaiko { - pub speed_change: Option, -} -impl DaycoreTaiko { - /// The acronym of [`DaycoreTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DaycoreTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`DaycoreTaiko`] - pub const fn description() -> &'static str { - "Whoaaaaa..." - } - /// The [`GameModKind`] of [`DaycoreTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } -} -impl<'de> Deserialize<'de> for DaycoreTaiko { - fn deserialize>(d: D) -> Result { - struct DaycoreTaikoVisitor; - impl<'de> Visitor<'de> for DaycoreTaikoVisitor { - type Value = DaycoreTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DaycoreTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - }) - } - } - d.deserialize_map(DaycoreTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DaycoreTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.speed_change.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - map.end() - } -} -/// Everything just got a bit harder... -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct HardRockTaiko {} -impl HardRockTaiko { - /// The acronym of [`HardRockTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HardRockTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("DA"), - ] - } - .into_iter() - } - /// The description of [`HardRockTaiko`] - pub const fn description() -> &'static str { - "Everything just got a bit harder..." - } - /// The [`GameModKind`] of [`HardRockTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`HardRockTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 16 - } -} -impl<'de> Deserialize<'de> for HardRockTaiko { - fn deserialize>(d: D) -> Result { - struct HardRockTaikoVisitor; - impl<'de> Visitor<'de> for HardRockTaikoVisitor { - type Value = HardRockTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HardRockTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(HardRockTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HardRockTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Miss and fail. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct SuddenDeathTaiko { - pub restart: Option, -} -impl SuddenDeathTaiko { - /// The acronym of [`SuddenDeathTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SuddenDeathTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`SuddenDeathTaiko`] - pub const fn description() -> &'static str { - "Miss and fail." - } - /// The [`GameModKind`] of [`SuddenDeathTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`SuddenDeathTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 32 - } -} -impl<'de> Deserialize<'de> for SuddenDeathTaiko { - fn deserialize>(d: D) -> Result { - struct SuddenDeathTaikoVisitor; - impl<'de> Visitor<'de> for SuddenDeathTaikoVisitor { - type Value = SuddenDeathTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SuddenDeathTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(SuddenDeathTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SuddenDeathTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// SS or quit. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct PerfectTaiko { - pub restart: Option, -} -impl PerfectTaiko { - /// The acronym of [`PerfectTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("PF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`PerfectTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`PerfectTaiko`] - pub const fn description() -> &'static str { - "SS or quit." - } - /// The [`GameModKind`] of [`PerfectTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`PerfectTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 16416 - } -} -impl<'de> Deserialize<'de> for PerfectTaiko { - fn deserialize>(d: D) -> Result { - struct PerfectTaikoVisitor; - impl<'de> Visitor<'de> for PerfectTaikoVisitor { - type Value = PerfectTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("PerfectTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(PerfectTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for PerfectTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// Zoooooooooom... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DoubleTimeTaiko { - pub speed_change: Option, - pub adjust_pitch: Option, -} -impl DoubleTimeTaiko { - /// The acronym of [`DoubleTimeTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DoubleTimeTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`DoubleTimeTaiko`] - pub const fn description() -> &'static str { - "Zoooooooooom..." - } - /// The [`GameModKind`] of [`DoubleTimeTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`DoubleTimeTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 64 - } -} -impl<'de> Deserialize<'de> for DoubleTimeTaiko { - fn deserialize>(d: D) -> Result { - struct DoubleTimeTaikoVisitor; - impl<'de> Visitor<'de> for DoubleTimeTaikoVisitor { - type Value = DoubleTimeTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DoubleTimeTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(DoubleTimeTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DoubleTimeTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.speed_change.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Uguuuuuuuu... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct NightcoreTaiko { - pub speed_change: Option, -} -impl NightcoreTaiko { - /// The acronym of [`NightcoreTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NightcoreTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`NightcoreTaiko`] - pub const fn description() -> &'static str { - "Uguuuuuuuu..." - } - /// The [`GameModKind`] of [`NightcoreTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`NightcoreTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 576 - } -} -impl<'de> Deserialize<'de> for NightcoreTaiko { - fn deserialize>(d: D) -> Result { - struct NightcoreTaikoVisitor; - impl<'de> Visitor<'de> for NightcoreTaikoVisitor { - type Value = NightcoreTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NightcoreTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - }) - } - } - d.deserialize_map(NightcoreTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NightcoreTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.speed_change.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - map.end() - } -} -/// Beats fade out before you hit them! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct HiddenTaiko {} -impl HiddenTaiko { - /// The acronym of [`HiddenTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HiddenTaiko`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`HiddenTaiko`] - pub const fn description() -> &'static str { - "Beats fade out before you hit them!" - } - /// The [`GameModKind`] of [`HiddenTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`HiddenTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 8 - } -} -impl<'de> Deserialize<'de> for HiddenTaiko { - fn deserialize>(d: D) -> Result { - struct HiddenTaikoVisitor; - impl<'de> Visitor<'de> for HiddenTaikoVisitor { - type Value = HiddenTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HiddenTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(HiddenTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HiddenTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Restricted view area. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct FlashlightTaiko { - pub size_multiplier: Option, - pub combo_based_size: Option, -} -impl FlashlightTaiko { - /// The acronym of [`FlashlightTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("FL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`FlashlightTaiko`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`FlashlightTaiko`] - pub const fn description() -> &'static str { - "Restricted view area." - } - /// The [`GameModKind`] of [`FlashlightTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`FlashlightTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 1024 - } -} -impl<'de> Deserialize<'de> for FlashlightTaiko { - fn deserialize>(d: D) -> Result { - struct FlashlightTaikoVisitor; - impl<'de> Visitor<'de> for FlashlightTaikoVisitor { - type Value = FlashlightTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("FlashlightTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut size_multiplier = None; - let mut combo_based_size = None; - while let Some(key) = map.next_key()? { - match key { - "size_multiplier" => size_multiplier = Some(map.next_value()?), - "combo_based_size" => combo_based_size = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - size_multiplier: size_multiplier.unwrap_or_default(), - combo_based_size: combo_based_size.unwrap_or_default(), - }) - } - } - d.deserialize_map(FlashlightTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for FlashlightTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.size_multiplier.is_some() as usize + self.combo_based_size.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.size_multiplier { - map.serialize_entry("size_multiplier", x)?; - } - if let Some(ref x) = self.combo_based_size { - map.serialize_entry("combo_based_size", x)?; - } - map.end() - } -} -/// Fail if your accuracy drops too low! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct AccuracyChallengeTaiko { - pub minimum_accuracy: Option, - pub accuracy_judge_mode: Option, - pub restart: Option, -} -impl AccuracyChallengeTaiko { - /// The acronym of [`AccuracyChallengeTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AccuracyChallengeTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`AccuracyChallengeTaiko`] - pub const fn description() -> &'static str { - "Fail if your accuracy drops too low!" - } - /// The [`GameModKind`] of [`AccuracyChallengeTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } -} -impl<'de> Deserialize<'de> for AccuracyChallengeTaiko { - fn deserialize>(d: D) -> Result { - struct AccuracyChallengeTaikoVisitor; - impl<'de> Visitor<'de> for AccuracyChallengeTaikoVisitor { - type Value = AccuracyChallengeTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AccuracyChallengeTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut minimum_accuracy = None; - let mut accuracy_judge_mode = None; - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "minimum_accuracy" => minimum_accuracy = Some(map.next_value()?), - "accuracy_judge_mode" => accuracy_judge_mode = Some(map.next_value()?), - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - minimum_accuracy: minimum_accuracy.unwrap_or_default(), - accuracy_judge_mode: accuracy_judge_mode.unwrap_or_default(), - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(AccuracyChallengeTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AccuracyChallengeTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.minimum_accuracy.is_some() as usize - + self.accuracy_judge_mode.is_some() as usize - + self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.minimum_accuracy { - map.serialize_entry("minimum_accuracy", x)?; - } - if let Some(ref x) = self.accuracy_judge_mode { - map.serialize_entry("accuracy_judge_mode", x)?; - } - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// Shuffle around the colours! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct RandomTaiko { - pub seed: Option, -} -impl RandomTaiko { - /// The acronym of [`RandomTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("RD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`RandomTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("SW")] }.into_iter() - } - /// The description of [`RandomTaiko`] - pub const fn description() -> &'static str { - "Shuffle around the colours!" - } - /// The [`GameModKind`] of [`RandomTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`RandomTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 2097152 - } -} -impl<'de> Deserialize<'de> for RandomTaiko { - fn deserialize>(d: D) -> Result { - struct RandomTaikoVisitor; - impl<'de> Visitor<'de> for RandomTaikoVisitor { - type Value = RandomTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("RandomTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut seed = None; - while let Some(key) = map.next_key()? { - match key { - "seed" => seed = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - seed: seed.unwrap_or_default(), - }) - } - } - d.deserialize_map(RandomTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for RandomTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.seed.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.seed { - map.serialize_entry("seed", x)?; - } - map.end() - } -} -/// Override a beatmap's difficulty settings. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DifficultyAdjustTaiko { - pub scroll_speed: Option, - pub drain_rate: Option, - pub overall_difficulty: Option, - pub extended_limits: Option, -} -impl DifficultyAdjustTaiko { - /// The acronym of [`DifficultyAdjustTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DA") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DifficultyAdjustTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("HR"), - ] - } - .into_iter() - } - /// The description of [`DifficultyAdjustTaiko`] - pub const fn description() -> &'static str { - "Override a beatmap's difficulty settings." - } - /// The [`GameModKind`] of [`DifficultyAdjustTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for DifficultyAdjustTaiko { - fn deserialize>(d: D) -> Result { - struct DifficultyAdjustTaikoVisitor; - impl<'de> Visitor<'de> for DifficultyAdjustTaikoVisitor { - type Value = DifficultyAdjustTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DifficultyAdjustTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut scroll_speed = None; - let mut drain_rate = None; - let mut overall_difficulty = None; - let mut extended_limits = None; - while let Some(key) = map.next_key()? { - match key { - "scroll_speed" => scroll_speed = Some(map.next_value()?), - "drain_rate" => drain_rate = Some(map.next_value()?), - "overall_difficulty" => overall_difficulty = Some(map.next_value()?), - "extended_limits" => extended_limits = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - scroll_speed: scroll_speed.unwrap_or_default(), - drain_rate: drain_rate.unwrap_or_default(), - overall_difficulty: overall_difficulty.unwrap_or_default(), - extended_limits: extended_limits.unwrap_or_default(), - }) - } - } - d.deserialize_map(DifficultyAdjustTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DifficultyAdjustTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.scroll_speed.is_some() as usize - + self.drain_rate.is_some() as usize - + self.overall_difficulty.is_some() as usize - + self.extended_limits.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.scroll_speed { - map.serialize_entry("scroll_speed", x)?; - } - if let Some(ref x) = self.drain_rate { - map.serialize_entry("drain_rate", x)?; - } - if let Some(ref x) = self.overall_difficulty { - map.serialize_entry("overall_difficulty", x)?; - } - if let Some(ref x) = self.extended_limits { - map.serialize_entry("extended_limits", x)?; - } - map.end() - } -} -/// Feeling nostalgic? -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ClassicTaiko {} -impl ClassicTaiko { - /// The acronym of [`ClassicTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ClassicTaiko`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`ClassicTaiko`] - pub const fn description() -> &'static str { - "Feeling nostalgic?" - } - /// The [`GameModKind`] of [`ClassicTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for ClassicTaiko { - fn deserialize>(d: D) -> Result { - struct ClassicTaikoVisitor; - impl<'de> Visitor<'de> for ClassicTaikoVisitor { - type Value = ClassicTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ClassicTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ClassicTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ClassicTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Dons become kats, kats become dons -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct SwapTaiko {} -impl SwapTaiko { - /// The acronym of [`SwapTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SW") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SwapTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("RD")] }.into_iter() - } - /// The description of [`SwapTaiko`] - pub const fn description() -> &'static str { - "Dons become kats, kats become dons" - } - /// The [`GameModKind`] of [`SwapTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for SwapTaiko { - fn deserialize>(d: D) -> Result { - struct SwapTaikoVisitor; - impl<'de> Visitor<'de> for SwapTaikoVisitor { - type Value = SwapTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SwapTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(SwapTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SwapTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// One key for dons, one key for kats. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct SingleTapTaiko {} -impl SingleTapTaiko { - /// The acronym of [`SingleTapTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SG") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SingleTapTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("RX"), - ] - } - .into_iter() - } - /// The description of [`SingleTapTaiko`] - pub const fn description() -> &'static str { - "One key for dons, one key for kats." - } - /// The [`GameModKind`] of [`SingleTapTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for SingleTapTaiko { - fn deserialize>(d: D) -> Result { - struct SingleTapTaikoVisitor; - impl<'de> Visitor<'de> for SingleTapTaikoVisitor { - type Value = SingleTapTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SingleTapTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(SingleTapTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SingleTapTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// No more tricky speed changes! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ConstantSpeedTaiko {} -impl ConstantSpeedTaiko { - /// The acronym of [`ConstantSpeedTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CS") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ConstantSpeedTaiko`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`ConstantSpeedTaiko`] - pub const fn description() -> &'static str { - "No more tricky speed changes!" - } - /// The [`GameModKind`] of [`ConstantSpeedTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for ConstantSpeedTaiko { - fn deserialize>(d: D) -> Result { - struct ConstantSpeedTaikoVisitor; - impl<'de> Visitor<'de> for ConstantSpeedTaikoVisitor { - type Value = ConstantSpeedTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ConstantSpeedTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ConstantSpeedTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ConstantSpeedTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Watch a perfect automated play through the song. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct AutoplayTaiko {} -impl AutoplayTaiko { - /// The acronym of [`AutoplayTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AutoplayTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SG"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("RX"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`AutoplayTaiko`] - pub const fn description() -> &'static str { - "Watch a perfect automated play through the song." - } - /// The [`GameModKind`] of [`AutoplayTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`AutoplayTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 2048 - } -} -impl<'de> Deserialize<'de> for AutoplayTaiko { - fn deserialize>(d: D) -> Result { - struct AutoplayTaikoVisitor; - impl<'de> Visitor<'de> for AutoplayTaikoVisitor { - type Value = AutoplayTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AutoplayTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(AutoplayTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AutoplayTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Watch the video without visual distractions. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct CinemaTaiko {} -impl CinemaTaiko { - /// The acronym of [`CinemaTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CN") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`CinemaTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("SG"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("RX"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`CinemaTaiko`] - pub const fn description() -> &'static str { - "Watch the video without visual distractions." - } - /// The [`GameModKind`] of [`CinemaTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`CinemaTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 4194304 - } -} -impl<'de> Deserialize<'de> for CinemaTaiko { - fn deserialize>(d: D) -> Result { - struct CinemaTaikoVisitor; - impl<'de> Visitor<'de> for CinemaTaikoVisitor { - type Value = CinemaTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("CinemaTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(CinemaTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for CinemaTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// No need to remember which key is correct anymore! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct RelaxTaiko {} -impl RelaxTaiko { - /// The acronym of [`RelaxTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("RX") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`RelaxTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SG"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`RelaxTaiko`] - pub const fn description() -> &'static str { - "No need to remember which key is correct anymore!" - } - /// The [`GameModKind`] of [`RelaxTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`RelaxTaiko`] - /// - /// See - pub const fn bits() -> u32 { - 128 - } -} -impl<'de> Deserialize<'de> for RelaxTaiko { - fn deserialize>(d: D) -> Result { - struct RelaxTaikoVisitor; - impl<'de> Visitor<'de> for RelaxTaikoVisitor { - type Value = RelaxTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("RelaxTaiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(RelaxTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for RelaxTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Can you keep up? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct WindUpTaiko { - pub initial_rate: Option, - pub final_rate: Option, - pub adjust_pitch: Option, -} -impl WindUpTaiko { - /// The acronym of [`WindUpTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("WU") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`WindUpTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`WindUpTaiko`] - pub const fn description() -> &'static str { - "Can you keep up?" - } - /// The [`GameModKind`] of [`WindUpTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for WindUpTaiko { - fn deserialize>(d: D) -> Result { - struct WindUpTaikoVisitor; - impl<'de> Visitor<'de> for WindUpTaikoVisitor { - type Value = WindUpTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("WindUpTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut final_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "final_rate" => final_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - final_rate: final_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(WindUpTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for WindUpTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.initial_rate.is_some() as usize - + self.final_rate.is_some() as usize - + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.final_rate { - map.serialize_entry("final_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Sloooow doooown... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct WindDownTaiko { - pub initial_rate: Option, - pub final_rate: Option, - pub adjust_pitch: Option, -} -impl WindDownTaiko { - /// The acronym of [`WindDownTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("WD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`WindDownTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`WindDownTaiko`] - pub const fn description() -> &'static str { - "Sloooow doooown..." - } - /// The [`GameModKind`] of [`WindDownTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for WindDownTaiko { - fn deserialize>(d: D) -> Result { - struct WindDownTaikoVisitor; - impl<'de> Visitor<'de> for WindDownTaikoVisitor { - type Value = WindDownTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("WindDownTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut final_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "final_rate" => final_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - final_rate: final_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(WindDownTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for WindDownTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.initial_rate.is_some() as usize - + self.final_rate.is_some() as usize - + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.final_rate { - map.serialize_entry("final_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Can you still feel the rhythm without music? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct MutedTaiko { - pub inverse_muting: Option, - pub enable_metronome: Option, - pub mute_combo_count: Option, - pub affects_hit_sounds: Option, -} -impl MutedTaiko { - /// The acronym of [`MutedTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("MU") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`MutedTaiko`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`MutedTaiko`] - pub const fn description() -> &'static str { - "Can you still feel the rhythm without music?" - } - /// The [`GameModKind`] of [`MutedTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for MutedTaiko { - fn deserialize>(d: D) -> Result { - struct MutedTaikoVisitor; - impl<'de> Visitor<'de> for MutedTaikoVisitor { - type Value = MutedTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("MutedTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut inverse_muting = None; - let mut enable_metronome = None; - let mut mute_combo_count = None; - let mut affects_hit_sounds = None; - while let Some(key) = map.next_key()? { - match key { - "inverse_muting" => inverse_muting = Some(map.next_value()?), - "enable_metronome" => enable_metronome = Some(map.next_value()?), - "mute_combo_count" => mute_combo_count = Some(map.next_value()?), - "affects_hit_sounds" => affects_hit_sounds = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - inverse_muting: inverse_muting.unwrap_or_default(), - enable_metronome: enable_metronome.unwrap_or_default(), - mute_combo_count: mute_combo_count.unwrap_or_default(), - affects_hit_sounds: affects_hit_sounds.unwrap_or_default(), - }) - } - } - d.deserialize_map(MutedTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for MutedTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.inverse_muting.is_some() as usize - + self.enable_metronome.is_some() as usize - + self.mute_combo_count.is_some() as usize - + self.affects_hit_sounds.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.inverse_muting { - map.serialize_entry("inverse_muting", x)?; - } - if let Some(ref x) = self.enable_metronome { - map.serialize_entry("enable_metronome", x)?; - } - if let Some(ref x) = self.mute_combo_count { - map.serialize_entry("mute_combo_count", x)?; - } - if let Some(ref x) = self.affects_hit_sounds { - map.serialize_entry("affects_hit_sounds", x)?; - } - map.end() - } -} -/// Let track speed adapt to you. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct AdaptiveSpeedTaiko { - pub initial_rate: Option, - pub adjust_pitch: Option, -} -impl AdaptiveSpeedTaiko { - /// The acronym of [`AdaptiveSpeedTaiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AS") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AdaptiveSpeedTaiko`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - ] - } - .into_iter() - } - /// The description of [`AdaptiveSpeedTaiko`] - pub const fn description() -> &'static str { - "Let track speed adapt to you." - } - /// The [`GameModKind`] of [`AdaptiveSpeedTaiko`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for AdaptiveSpeedTaiko { - fn deserialize>(d: D) -> Result { - struct AdaptiveSpeedTaikoVisitor; - impl<'de> Visitor<'de> for AdaptiveSpeedTaikoVisitor { - type Value = AdaptiveSpeedTaiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AdaptiveSpeedTaiko") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(AdaptiveSpeedTaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AdaptiveSpeedTaiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.initial_rate.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Score set on earlier osu! versions with the V2 scoring algorithm active. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ScoreV2Taiko {} -impl ScoreV2Taiko { - /// The acronym of [`ScoreV2Taiko`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SV2") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ScoreV2Taiko`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`ScoreV2Taiko`] - pub const fn description() -> &'static str { - "Score set on earlier osu! versions with the V2 scoring algorithm active." - } - /// The [`GameModKind`] of [`ScoreV2Taiko`] - pub const fn kind() -> GameModKind { - GameModKind::System - } - /// Bit value of [`ScoreV2Taiko`] - /// - /// See - pub const fn bits() -> u32 { - 536870912 - } -} -impl<'de> Deserialize<'de> for ScoreV2Taiko { - fn deserialize>(d: D) -> Result { - struct ScoreV2TaikoVisitor; - impl<'de> Visitor<'de> for ScoreV2TaikoVisitor { - type Value = ScoreV2Taiko; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ScoreV2Taiko") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ScoreV2TaikoVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ScoreV2Taiko { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Larger fruits, more forgiving HP drain, less accuracy required, and three lives! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct EasyCatch { - pub retries: Option, -} -impl EasyCatch { - /// The acronym of [`EasyCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("EZ") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`EasyCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HR"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("DA"), - ] - } - .into_iter() - } - /// The description of [`EasyCatch`] - pub const fn description() -> &'static str { - "Larger fruits, more forgiving HP drain, less accuracy required, and three lives!" - } - /// The [`GameModKind`] of [`EasyCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`EasyCatch`] - /// - /// See - pub const fn bits() -> u32 { - 2 - } -} -impl<'de> Deserialize<'de> for EasyCatch { - fn deserialize>(d: D) -> Result { - struct EasyCatchVisitor; - impl<'de> Visitor<'de> for EasyCatchVisitor { - type Value = EasyCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("EasyCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut retries = None; - while let Some(key) = map.next_key()? { - match key { - "retries" => retries = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - retries: retries.unwrap_or_default(), - }) - } - } - d.deserialize_map(EasyCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for EasyCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.retries.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.retries { - map.serialize_entry("retries", x)?; - } - map.end() - } -} -/// You can't fail, no matter what. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct NoFailCatch {} -impl NoFailCatch { - /// The acronym of [`NoFailCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NoFailCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`NoFailCatch`] - pub const fn description() -> &'static str { - "You can't fail, no matter what." - } - /// The [`GameModKind`] of [`NoFailCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`NoFailCatch`] - /// - /// See - pub const fn bits() -> u32 { - 1 - } -} -impl<'de> Deserialize<'de> for NoFailCatch { - fn deserialize>(d: D) -> Result { - struct NoFailCatchVisitor; - impl<'de> Visitor<'de> for NoFailCatchVisitor { - type Value = NoFailCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NoFailCatch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(NoFailCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NoFailCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Less zoom... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct HalfTimeCatch { - pub speed_change: Option, - pub adjust_pitch: Option, -} -impl HalfTimeCatch { - /// The acronym of [`HalfTimeCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HalfTimeCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - ] - } - .into_iter() - } - /// The description of [`HalfTimeCatch`] - pub const fn description() -> &'static str { - "Less zoom..." - } - /// The [`GameModKind`] of [`HalfTimeCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`HalfTimeCatch`] - /// - /// See - pub const fn bits() -> u32 { - 256 - } -} -impl<'de> Deserialize<'de> for HalfTimeCatch { - fn deserialize>(d: D) -> Result { - struct HalfTimeCatchVisitor; - impl<'de> Visitor<'de> for HalfTimeCatchVisitor { - type Value = HalfTimeCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HalfTimeCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(HalfTimeCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HalfTimeCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.speed_change.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Whoaaaaa... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DaycoreCatch { - pub speed_change: Option, -} -impl DaycoreCatch { - /// The acronym of [`DaycoreCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DaycoreCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - ] - } - .into_iter() - } - /// The description of [`DaycoreCatch`] - pub const fn description() -> &'static str { - "Whoaaaaa..." - } - /// The [`GameModKind`] of [`DaycoreCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } -} -impl<'de> Deserialize<'de> for DaycoreCatch { - fn deserialize>(d: D) -> Result { - struct DaycoreCatchVisitor; - impl<'de> Visitor<'de> for DaycoreCatchVisitor { - type Value = DaycoreCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DaycoreCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - }) - } - } - d.deserialize_map(DaycoreCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DaycoreCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.speed_change.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - map.end() - } -} -/// Everything just got a bit harder... -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct HardRockCatch {} -impl HardRockCatch { - /// The acronym of [`HardRockCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HardRockCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("DA"), - ] - } - .into_iter() - } - /// The description of [`HardRockCatch`] - pub const fn description() -> &'static str { - "Everything just got a bit harder..." - } - /// The [`GameModKind`] of [`HardRockCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`HardRockCatch`] - /// - /// See - pub const fn bits() -> u32 { - 16 - } -} -impl<'de> Deserialize<'de> for HardRockCatch { - fn deserialize>(d: D) -> Result { - struct HardRockCatchVisitor; - impl<'de> Visitor<'de> for HardRockCatchVisitor { - type Value = HardRockCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HardRockCatch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(HardRockCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HardRockCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Miss and fail. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct SuddenDeathCatch { - pub restart: Option, -} -impl SuddenDeathCatch { - /// The acronym of [`SuddenDeathCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SuddenDeathCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`SuddenDeathCatch`] - pub const fn description() -> &'static str { - "Miss and fail." - } - /// The [`GameModKind`] of [`SuddenDeathCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`SuddenDeathCatch`] - /// - /// See - pub const fn bits() -> u32 { - 32 - } -} -impl<'de> Deserialize<'de> for SuddenDeathCatch { - fn deserialize>(d: D) -> Result { - struct SuddenDeathCatchVisitor; - impl<'de> Visitor<'de> for SuddenDeathCatchVisitor { - type Value = SuddenDeathCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SuddenDeathCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(SuddenDeathCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SuddenDeathCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// SS or quit. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct PerfectCatch { - pub restart: Option, -} -impl PerfectCatch { - /// The acronym of [`PerfectCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("PF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`PerfectCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`PerfectCatch`] - pub const fn description() -> &'static str { - "SS or quit." - } - /// The [`GameModKind`] of [`PerfectCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`PerfectCatch`] - /// - /// See - pub const fn bits() -> u32 { - 16416 - } -} -impl<'de> Deserialize<'de> for PerfectCatch { - fn deserialize>(d: D) -> Result { - struct PerfectCatchVisitor; - impl<'de> Visitor<'de> for PerfectCatchVisitor { - type Value = PerfectCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("PerfectCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(PerfectCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for PerfectCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// Zoooooooooom... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DoubleTimeCatch { - pub speed_change: Option, - pub adjust_pitch: Option, -} -impl DoubleTimeCatch { - /// The acronym of [`DoubleTimeCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DoubleTimeCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - ] - } - .into_iter() - } - /// The description of [`DoubleTimeCatch`] - pub const fn description() -> &'static str { - "Zoooooooooom..." - } - /// The [`GameModKind`] of [`DoubleTimeCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`DoubleTimeCatch`] - /// - /// See - pub const fn bits() -> u32 { - 64 - } -} -impl<'de> Deserialize<'de> for DoubleTimeCatch { - fn deserialize>(d: D) -> Result { - struct DoubleTimeCatchVisitor; - impl<'de> Visitor<'de> for DoubleTimeCatchVisitor { - type Value = DoubleTimeCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DoubleTimeCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(DoubleTimeCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DoubleTimeCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.speed_change.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Uguuuuuuuu... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct NightcoreCatch { - pub speed_change: Option, -} -impl NightcoreCatch { - /// The acronym of [`NightcoreCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NightcoreCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - ] - } - .into_iter() - } - /// The description of [`NightcoreCatch`] - pub const fn description() -> &'static str { - "Uguuuuuuuu..." - } - /// The [`GameModKind`] of [`NightcoreCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`NightcoreCatch`] - /// - /// See - pub const fn bits() -> u32 { - 576 - } -} -impl<'de> Deserialize<'de> for NightcoreCatch { - fn deserialize>(d: D) -> Result { - struct NightcoreCatchVisitor; - impl<'de> Visitor<'de> for NightcoreCatchVisitor { - type Value = NightcoreCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NightcoreCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - }) - } - } - d.deserialize_map(NightcoreCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NightcoreCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.speed_change.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - map.end() - } -} -/// Play with fading fruits. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct HiddenCatch {} -impl HiddenCatch { - /// The acronym of [`HiddenCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HiddenCatch`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`HiddenCatch`] - pub const fn description() -> &'static str { - "Play with fading fruits." - } - /// The [`GameModKind`] of [`HiddenCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`HiddenCatch`] - /// - /// See - pub const fn bits() -> u32 { - 8 - } -} -impl<'de> Deserialize<'de> for HiddenCatch { - fn deserialize>(d: D) -> Result { - struct HiddenCatchVisitor; - impl<'de> Visitor<'de> for HiddenCatchVisitor { - type Value = HiddenCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HiddenCatch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(HiddenCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HiddenCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Restricted view area. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct FlashlightCatch { - pub size_multiplier: Option, - pub combo_based_size: Option, -} -impl FlashlightCatch { - /// The acronym of [`FlashlightCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("FL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`FlashlightCatch`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`FlashlightCatch`] - pub const fn description() -> &'static str { - "Restricted view area." - } - /// The [`GameModKind`] of [`FlashlightCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`FlashlightCatch`] - /// - /// See - pub const fn bits() -> u32 { - 1024 - } -} -impl<'de> Deserialize<'de> for FlashlightCatch { - fn deserialize>(d: D) -> Result { - struct FlashlightCatchVisitor; - impl<'de> Visitor<'de> for FlashlightCatchVisitor { - type Value = FlashlightCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("FlashlightCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut size_multiplier = None; - let mut combo_based_size = None; - while let Some(key) = map.next_key()? { - match key { - "size_multiplier" => size_multiplier = Some(map.next_value()?), - "combo_based_size" => combo_based_size = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - size_multiplier: size_multiplier.unwrap_or_default(), - combo_based_size: combo_based_size.unwrap_or_default(), - }) - } - } - d.deserialize_map(FlashlightCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for FlashlightCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.size_multiplier.is_some() as usize + self.combo_based_size.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.size_multiplier { - map.serialize_entry("size_multiplier", x)?; - } - if let Some(ref x) = self.combo_based_size { - map.serialize_entry("combo_based_size", x)?; - } - map.end() - } -} -/// Fail if your accuracy drops too low! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct AccuracyChallengeCatch { - pub minimum_accuracy: Option, - pub accuracy_judge_mode: Option, - pub restart: Option, -} -impl AccuracyChallengeCatch { - /// The acronym of [`AccuracyChallengeCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AccuracyChallengeCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`AccuracyChallengeCatch`] - pub const fn description() -> &'static str { - "Fail if your accuracy drops too low!" - } - /// The [`GameModKind`] of [`AccuracyChallengeCatch`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } -} -impl<'de> Deserialize<'de> for AccuracyChallengeCatch { - fn deserialize>(d: D) -> Result { - struct AccuracyChallengeCatchVisitor; - impl<'de> Visitor<'de> for AccuracyChallengeCatchVisitor { - type Value = AccuracyChallengeCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AccuracyChallengeCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut minimum_accuracy = None; - let mut accuracy_judge_mode = None; - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "minimum_accuracy" => minimum_accuracy = Some(map.next_value()?), - "accuracy_judge_mode" => accuracy_judge_mode = Some(map.next_value()?), - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - minimum_accuracy: minimum_accuracy.unwrap_or_default(), - accuracy_judge_mode: accuracy_judge_mode.unwrap_or_default(), - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(AccuracyChallengeCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AccuracyChallengeCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.minimum_accuracy.is_some() as usize - + self.accuracy_judge_mode.is_some() as usize - + self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.minimum_accuracy { - map.serialize_entry("minimum_accuracy", x)?; - } - if let Some(ref x) = self.accuracy_judge_mode { - map.serialize_entry("accuracy_judge_mode", x)?; - } - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// Override a beatmap's difficulty settings. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DifficultyAdjustCatch { - pub circle_size: Option, - pub approach_rate: Option, - pub hard_rock_offsets: Option, - pub drain_rate: Option, - pub overall_difficulty: Option, - pub extended_limits: Option, -} -impl DifficultyAdjustCatch { - /// The acronym of [`DifficultyAdjustCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DA") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DifficultyAdjustCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("HR"), - ] - } - .into_iter() - } - /// The description of [`DifficultyAdjustCatch`] - pub const fn description() -> &'static str { - "Override a beatmap's difficulty settings." - } - /// The [`GameModKind`] of [`DifficultyAdjustCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for DifficultyAdjustCatch { - fn deserialize>(d: D) -> Result { - struct DifficultyAdjustCatchVisitor; - impl<'de> Visitor<'de> for DifficultyAdjustCatchVisitor { - type Value = DifficultyAdjustCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DifficultyAdjustCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut circle_size = None; - let mut approach_rate = None; - let mut hard_rock_offsets = None; - let mut drain_rate = None; - let mut overall_difficulty = None; - let mut extended_limits = None; - while let Some(key) = map.next_key()? { - match key { - "circle_size" => circle_size = Some(map.next_value()?), - "approach_rate" => approach_rate = Some(map.next_value()?), - "hard_rock_offsets" => hard_rock_offsets = Some(map.next_value()?), - "drain_rate" => drain_rate = Some(map.next_value()?), - "overall_difficulty" => overall_difficulty = Some(map.next_value()?), - "extended_limits" => extended_limits = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - circle_size: circle_size.unwrap_or_default(), - approach_rate: approach_rate.unwrap_or_default(), - hard_rock_offsets: hard_rock_offsets.unwrap_or_default(), - drain_rate: drain_rate.unwrap_or_default(), - overall_difficulty: overall_difficulty.unwrap_or_default(), - extended_limits: extended_limits.unwrap_or_default(), - }) - } - } - d.deserialize_map(DifficultyAdjustCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DifficultyAdjustCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.circle_size.is_some() as usize - + self.approach_rate.is_some() as usize - + self.hard_rock_offsets.is_some() as usize - + self.drain_rate.is_some() as usize - + self.overall_difficulty.is_some() as usize - + self.extended_limits.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.circle_size { - map.serialize_entry("circle_size", x)?; - } - if let Some(ref x) = self.approach_rate { - map.serialize_entry("approach_rate", x)?; - } - if let Some(ref x) = self.hard_rock_offsets { - map.serialize_entry("hard_rock_offsets", x)?; - } - if let Some(ref x) = self.drain_rate { - map.serialize_entry("drain_rate", x)?; - } - if let Some(ref x) = self.overall_difficulty { - map.serialize_entry("overall_difficulty", x)?; - } - if let Some(ref x) = self.extended_limits { - map.serialize_entry("extended_limits", x)?; - } - map.end() - } -} -/// Feeling nostalgic? -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ClassicCatch {} -impl ClassicCatch { - /// The acronym of [`ClassicCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ClassicCatch`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`ClassicCatch`] - pub const fn description() -> &'static str { - "Feeling nostalgic?" - } - /// The [`GameModKind`] of [`ClassicCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for ClassicCatch { - fn deserialize>(d: D) -> Result { - struct ClassicCatchVisitor; - impl<'de> Visitor<'de> for ClassicCatchVisitor { - type Value = ClassicCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ClassicCatch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ClassicCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ClassicCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Fruits are flipped horizontally. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct MirrorCatch {} -impl MirrorCatch { - /// The acronym of [`MirrorCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("MR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`MirrorCatch`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`MirrorCatch`] - pub const fn description() -> &'static str { - "Fruits are flipped horizontally." - } - /// The [`GameModKind`] of [`MirrorCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`MirrorCatch`] - /// - /// See - pub const fn bits() -> u32 { - 1073741824 - } -} -impl<'de> Deserialize<'de> for MirrorCatch { - fn deserialize>(d: D) -> Result { - struct MirrorCatchVisitor; - impl<'de> Visitor<'de> for MirrorCatchVisitor { - type Value = MirrorCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("MirrorCatch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(MirrorCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for MirrorCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Watch a perfect automated play through the song. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct AutoplayCatch {} -impl AutoplayCatch { - /// The acronym of [`AutoplayCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AutoplayCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("RX"), - ] - } - .into_iter() - } - /// The description of [`AutoplayCatch`] - pub const fn description() -> &'static str { - "Watch a perfect automated play through the song." - } - /// The [`GameModKind`] of [`AutoplayCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`AutoplayCatch`] - /// - /// See - pub const fn bits() -> u32 { - 2048 - } -} -impl<'de> Deserialize<'de> for AutoplayCatch { - fn deserialize>(d: D) -> Result { - struct AutoplayCatchVisitor; - impl<'de> Visitor<'de> for AutoplayCatchVisitor { - type Value = AutoplayCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AutoplayCatch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(AutoplayCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AutoplayCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Watch the video without visual distractions. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct CinemaCatch {} -impl CinemaCatch { - /// The acronym of [`CinemaCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CN") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`CinemaCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("RX"), - ] - } - .into_iter() - } - /// The description of [`CinemaCatch`] - pub const fn description() -> &'static str { - "Watch the video without visual distractions." - } - /// The [`GameModKind`] of [`CinemaCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`CinemaCatch`] - /// - /// See - pub const fn bits() -> u32 { - 4194304 - } -} -impl<'de> Deserialize<'de> for CinemaCatch { - fn deserialize>(d: D) -> Result { - struct CinemaCatchVisitor; - impl<'de> Visitor<'de> for CinemaCatchVisitor { - type Value = CinemaCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("CinemaCatch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(CinemaCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for CinemaCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Use the mouse to control the catcher. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct RelaxCatch {} -impl RelaxCatch { - /// The acronym of [`RelaxCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("RX") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`RelaxCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`RelaxCatch`] - pub const fn description() -> &'static str { - "Use the mouse to control the catcher." - } - /// The [`GameModKind`] of [`RelaxCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`RelaxCatch`] - /// - /// See - pub const fn bits() -> u32 { - 128 - } -} -impl<'de> Deserialize<'de> for RelaxCatch { - fn deserialize>(d: D) -> Result { - struct RelaxCatchVisitor; - impl<'de> Visitor<'de> for RelaxCatchVisitor { - type Value = RelaxCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("RelaxCatch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(RelaxCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for RelaxCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Can you keep up? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct WindUpCatch { - pub initial_rate: Option, - pub final_rate: Option, - pub adjust_pitch: Option, -} -impl WindUpCatch { - /// The acronym of [`WindUpCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("WU") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`WindUpCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WD"), - ] - } - .into_iter() - } - /// The description of [`WindUpCatch`] - pub const fn description() -> &'static str { - "Can you keep up?" - } - /// The [`GameModKind`] of [`WindUpCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for WindUpCatch { - fn deserialize>(d: D) -> Result { - struct WindUpCatchVisitor; - impl<'de> Visitor<'de> for WindUpCatchVisitor { - type Value = WindUpCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("WindUpCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut final_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "final_rate" => final_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - final_rate: final_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(WindUpCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for WindUpCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.initial_rate.is_some() as usize - + self.final_rate.is_some() as usize - + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.final_rate { - map.serialize_entry("final_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Sloooow doooown... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct WindDownCatch { - pub initial_rate: Option, - pub final_rate: Option, - pub adjust_pitch: Option, -} -impl WindDownCatch { - /// The acronym of [`WindDownCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("WD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`WindDownCatch`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - ] - } - .into_iter() - } - /// The description of [`WindDownCatch`] - pub const fn description() -> &'static str { - "Sloooow doooown..." - } - /// The [`GameModKind`] of [`WindDownCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for WindDownCatch { - fn deserialize>(d: D) -> Result { - struct WindDownCatchVisitor; - impl<'de> Visitor<'de> for WindDownCatchVisitor { - type Value = WindDownCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("WindDownCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut final_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "final_rate" => final_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - final_rate: final_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(WindDownCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for WindDownCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.initial_rate.is_some() as usize - + self.final_rate.is_some() as usize - + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.final_rate { - map.serialize_entry("final_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// The fruits are... floating? -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct FloatingFruitsCatch {} -impl FloatingFruitsCatch { - /// The acronym of [`FloatingFruitsCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("FF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`FloatingFruitsCatch`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`FloatingFruitsCatch`] - pub const fn description() -> &'static str { - "The fruits are... floating?" - } - /// The [`GameModKind`] of [`FloatingFruitsCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for FloatingFruitsCatch { - fn deserialize>(d: D) -> Result { - struct FloatingFruitsCatchVisitor; - impl<'de> Visitor<'de> for FloatingFruitsCatchVisitor { - type Value = FloatingFruitsCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("FloatingFruitsCatch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(FloatingFruitsCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for FloatingFruitsCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Can you still feel the rhythm without music? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct MutedCatch { - pub inverse_muting: Option, - pub enable_metronome: Option, - pub mute_combo_count: Option, - pub affects_hit_sounds: Option, -} -impl MutedCatch { - /// The acronym of [`MutedCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("MU") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`MutedCatch`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`MutedCatch`] - pub const fn description() -> &'static str { - "Can you still feel the rhythm without music?" - } - /// The [`GameModKind`] of [`MutedCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for MutedCatch { - fn deserialize>(d: D) -> Result { - struct MutedCatchVisitor; - impl<'de> Visitor<'de> for MutedCatchVisitor { - type Value = MutedCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("MutedCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut inverse_muting = None; - let mut enable_metronome = None; - let mut mute_combo_count = None; - let mut affects_hit_sounds = None; - while let Some(key) = map.next_key()? { - match key { - "inverse_muting" => inverse_muting = Some(map.next_value()?), - "enable_metronome" => enable_metronome = Some(map.next_value()?), - "mute_combo_count" => mute_combo_count = Some(map.next_value()?), - "affects_hit_sounds" => affects_hit_sounds = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - inverse_muting: inverse_muting.unwrap_or_default(), - enable_metronome: enable_metronome.unwrap_or_default(), - mute_combo_count: mute_combo_count.unwrap_or_default(), - affects_hit_sounds: affects_hit_sounds.unwrap_or_default(), - }) - } - } - d.deserialize_map(MutedCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for MutedCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.inverse_muting.is_some() as usize - + self.enable_metronome.is_some() as usize - + self.mute_combo_count.is_some() as usize - + self.affects_hit_sounds.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.inverse_muting { - map.serialize_entry("inverse_muting", x)?; - } - if let Some(ref x) = self.enable_metronome { - map.serialize_entry("enable_metronome", x)?; - } - if let Some(ref x) = self.mute_combo_count { - map.serialize_entry("mute_combo_count", x)?; - } - if let Some(ref x) = self.affects_hit_sounds { - map.serialize_entry("affects_hit_sounds", x)?; - } - map.end() - } -} -/// Where's the catcher? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct NoScopeCatch { - pub hidden_combo_count: Option, -} -impl NoScopeCatch { - /// The acronym of [`NoScopeCatch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NS") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NoScopeCatch`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`NoScopeCatch`] - pub const fn description() -> &'static str { - "Where's the catcher?" - } - /// The [`GameModKind`] of [`NoScopeCatch`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for NoScopeCatch { - fn deserialize>(d: D) -> Result { - struct NoScopeCatchVisitor; - impl<'de> Visitor<'de> for NoScopeCatchVisitor { - type Value = NoScopeCatch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NoScopeCatch") - } - fn visit_map>(self, mut map: A) -> Result { - let mut hidden_combo_count = None; - while let Some(key) = map.next_key()? { - match key { - "hidden_combo_count" => hidden_combo_count = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - hidden_combo_count: hidden_combo_count.unwrap_or_default(), - }) - } - } - d.deserialize_map(NoScopeCatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NoScopeCatch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.hidden_combo_count.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.hidden_combo_count { - map.serialize_entry("hidden_combo_count", x)?; - } - map.end() - } -} -/// Score set on earlier osu! versions with the V2 scoring algorithm active. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ScoreV2Catch {} -impl ScoreV2Catch { - /// The acronym of [`ScoreV2Catch`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SV2") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ScoreV2Catch`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`ScoreV2Catch`] - pub const fn description() -> &'static str { - "Score set on earlier osu! versions with the V2 scoring algorithm active." - } - /// The [`GameModKind`] of [`ScoreV2Catch`] - pub const fn kind() -> GameModKind { - GameModKind::System - } - /// Bit value of [`ScoreV2Catch`] - /// - /// See - pub const fn bits() -> u32 { - 536870912 - } -} -impl<'de> Deserialize<'de> for ScoreV2Catch { - fn deserialize>(d: D) -> Result { - struct ScoreV2CatchVisitor; - impl<'de> Visitor<'de> for ScoreV2CatchVisitor { - type Value = ScoreV2Catch; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ScoreV2Catch") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ScoreV2CatchVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ScoreV2Catch { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// More forgiving HP drain, less accuracy required, and three lives! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct EasyMania { - pub retries: Option, -} -impl EasyMania { - /// The acronym of [`EasyMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("EZ") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`EasyMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HR"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("DA"), - ] - } - .into_iter() - } - /// The description of [`EasyMania`] - pub const fn description() -> &'static str { - "More forgiving HP drain, less accuracy required, and three lives!" - } - /// The [`GameModKind`] of [`EasyMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`EasyMania`] - /// - /// See - pub const fn bits() -> u32 { - 2 - } -} -impl<'de> Deserialize<'de> for EasyMania { - fn deserialize>(d: D) -> Result { - struct EasyManiaVisitor; - impl<'de> Visitor<'de> for EasyManiaVisitor { - type Value = EasyMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("EasyMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut retries = None; - while let Some(key) = map.next_key()? { - match key { - "retries" => retries = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - retries: retries.unwrap_or_default(), - }) - } - } - d.deserialize_map(EasyManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for EasyMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.retries.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.retries { - map.serialize_entry("retries", x)?; - } - map.end() - } -} -/// You can't fail, no matter what. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct NoFailMania {} -impl NoFailMania { - /// The acronym of [`NoFailMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NoFailMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`NoFailMania`] - pub const fn description() -> &'static str { - "You can't fail, no matter what." - } - /// The [`GameModKind`] of [`NoFailMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`NoFailMania`] - /// - /// See - pub const fn bits() -> u32 { - 1 - } -} -impl<'de> Deserialize<'de> for NoFailMania { - fn deserialize>(d: D) -> Result { - struct NoFailManiaVisitor; - impl<'de> Visitor<'de> for NoFailManiaVisitor { - type Value = NoFailMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NoFailMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(NoFailManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NoFailMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Less zoom... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct HalfTimeMania { - pub speed_change: Option, - pub adjust_pitch: Option, -} -impl HalfTimeMania { - /// The acronym of [`HalfTimeMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HalfTimeMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`HalfTimeMania`] - pub const fn description() -> &'static str { - "Less zoom..." - } - /// The [`GameModKind`] of [`HalfTimeMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } - /// Bit value of [`HalfTimeMania`] - /// - /// See - pub const fn bits() -> u32 { - 256 - } -} -impl<'de> Deserialize<'de> for HalfTimeMania { - fn deserialize>(d: D) -> Result { - struct HalfTimeManiaVisitor; - impl<'de> Visitor<'de> for HalfTimeManiaVisitor { - type Value = HalfTimeMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HalfTimeMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(HalfTimeManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HalfTimeMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.speed_change.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Whoaaaaa... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DaycoreMania { - pub speed_change: Option, -} -impl DaycoreMania { - /// The acronym of [`DaycoreMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DaycoreMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`DaycoreMania`] - pub const fn description() -> &'static str { - "Whoaaaaa..." - } - /// The [`GameModKind`] of [`DaycoreMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyReduction - } -} -impl<'de> Deserialize<'de> for DaycoreMania { - fn deserialize>(d: D) -> Result { - struct DaycoreManiaVisitor; - impl<'de> Visitor<'de> for DaycoreManiaVisitor { - type Value = DaycoreMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DaycoreMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - }) - } - } - d.deserialize_map(DaycoreManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DaycoreMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.speed_change.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - map.end() - } -} -/// Everything just got a bit harder... -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct HardRockMania {} -impl HardRockMania { - /// The acronym of [`HardRockMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HardRockMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("DA"), - ] - } - .into_iter() - } - /// The description of [`HardRockMania`] - pub const fn description() -> &'static str { - "Everything just got a bit harder..." - } - /// The [`GameModKind`] of [`HardRockMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`HardRockMania`] - /// - /// See - pub const fn bits() -> u32 { - 16 - } -} -impl<'de> Deserialize<'de> for HardRockMania { - fn deserialize>(d: D) -> Result { - struct HardRockManiaVisitor; - impl<'de> Visitor<'de> for HardRockManiaVisitor { - type Value = HardRockMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HardRockMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(HardRockManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HardRockMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Miss and fail. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct SuddenDeathMania { - pub restart: Option, -} -impl SuddenDeathMania { - /// The acronym of [`SuddenDeathMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SuddenDeathMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`SuddenDeathMania`] - pub const fn description() -> &'static str { - "Miss and fail." - } - /// The [`GameModKind`] of [`SuddenDeathMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`SuddenDeathMania`] - /// - /// See - pub const fn bits() -> u32 { - 32 - } -} -impl<'de> Deserialize<'de> for SuddenDeathMania { - fn deserialize>(d: D) -> Result { - struct SuddenDeathManiaVisitor; - impl<'de> Visitor<'de> for SuddenDeathManiaVisitor { - type Value = SuddenDeathMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SuddenDeathMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(SuddenDeathManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SuddenDeathMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// SS or quit. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct PerfectMania { - pub restart: Option, -} -impl PerfectMania { - /// The acronym of [`PerfectMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("PF") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`PerfectMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`PerfectMania`] - pub const fn description() -> &'static str { - "SS or quit." - } - /// The [`GameModKind`] of [`PerfectMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`PerfectMania`] - /// - /// See - pub const fn bits() -> u32 { - 16416 - } -} -impl<'de> Deserialize<'de> for PerfectMania { - fn deserialize>(d: D) -> Result { - struct PerfectManiaVisitor; - impl<'de> Visitor<'de> for PerfectManiaVisitor { - type Value = PerfectMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("PerfectMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(PerfectManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for PerfectMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// Zoooooooooom... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DoubleTimeMania { - pub speed_change: Option, - pub adjust_pitch: Option, -} -impl DoubleTimeMania { - /// The acronym of [`DoubleTimeMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DoubleTimeMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`DoubleTimeMania`] - pub const fn description() -> &'static str { - "Zoooooooooom..." - } - /// The [`GameModKind`] of [`DoubleTimeMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`DoubleTimeMania`] - /// - /// See - pub const fn bits() -> u32 { - 64 - } -} -impl<'de> Deserialize<'de> for DoubleTimeMania { - fn deserialize>(d: D) -> Result { - struct DoubleTimeManiaVisitor; - impl<'de> Visitor<'de> for DoubleTimeManiaVisitor { - type Value = DoubleTimeMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DoubleTimeMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(DoubleTimeManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DoubleTimeMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.speed_change.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Uguuuuuuuu... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct NightcoreMania { - pub speed_change: Option, -} -impl NightcoreMania { - /// The acronym of [`NightcoreMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("NC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NightcoreMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`NightcoreMania`] - pub const fn description() -> &'static str { - "Uguuuuuuuu..." - } - /// The [`GameModKind`] of [`NightcoreMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`NightcoreMania`] - /// - /// See - pub const fn bits() -> u32 { - 576 - } -} -impl<'de> Deserialize<'de> for NightcoreMania { - fn deserialize>(d: D) -> Result { - struct NightcoreManiaVisitor; - impl<'de> Visitor<'de> for NightcoreManiaVisitor { - type Value = NightcoreMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NightcoreMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut speed_change = None; - while let Some(key) = map.next_key()? { - match key { - "speed_change" => speed_change = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - speed_change: speed_change.unwrap_or_default(), - }) - } - } - d.deserialize_map(NightcoreManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NightcoreMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.speed_change.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.speed_change { - map.serialize_entry("speed_change", x)?; - } - map.end() - } -} -/// Keys appear out of nowhere! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct FadeInMania {} -impl FadeInMania { - /// The acronym of [`FadeInMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("FI") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`FadeInMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HD"), - Acronym::from_str_unchecked("CO"), - Acronym::from_str_unchecked("FL"), - ] - } - .into_iter() - } - /// The description of [`FadeInMania`] - pub const fn description() -> &'static str { - "Keys appear out of nowhere!" - } - /// The [`GameModKind`] of [`FadeInMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`FadeInMania`] - /// - /// See - pub const fn bits() -> u32 { - 1048576 - } -} -impl<'de> Deserialize<'de> for FadeInMania { - fn deserialize>(d: D) -> Result { - struct FadeInManiaVisitor; - impl<'de> Visitor<'de> for FadeInManiaVisitor { - type Value = FadeInMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("FadeInMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(FadeInManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for FadeInMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Keys fade out before you hit them! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct HiddenMania {} -impl HiddenMania { - /// The acronym of [`HiddenMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HiddenMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("FI"), - Acronym::from_str_unchecked("CO"), - Acronym::from_str_unchecked("FL"), - ] - } - .into_iter() - } - /// The description of [`HiddenMania`] - pub const fn description() -> &'static str { - "Keys fade out before you hit them!" - } - /// The [`GameModKind`] of [`HiddenMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`HiddenMania`] - /// - /// See - pub const fn bits() -> u32 { - 8 - } -} -impl<'de> Deserialize<'de> for HiddenMania { - fn deserialize>(d: D) -> Result { - struct HiddenManiaVisitor; - impl<'de> Visitor<'de> for HiddenManiaVisitor { - type Value = HiddenMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HiddenMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(HiddenManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HiddenMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Decrease the playfield's viewing area. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct CoverMania { - pub coverage: Option, - pub direction: Option, -} -impl CoverMania { - /// The acronym of [`CoverMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CO") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`CoverMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("FI"), - Acronym::from_str_unchecked("HD"), - Acronym::from_str_unchecked("FL"), - ] - } - .into_iter() - } - /// The description of [`CoverMania`] - pub const fn description() -> &'static str { - "Decrease the playfield's viewing area." - } - /// The [`GameModKind`] of [`CoverMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } -} -impl<'de> Deserialize<'de> for CoverMania { - fn deserialize>(d: D) -> Result { - struct CoverManiaVisitor; - impl<'de> Visitor<'de> for CoverManiaVisitor { - type Value = CoverMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("CoverMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut coverage = None; - let mut direction = None; - while let Some(key) = map.next_key()? { - match key { - "coverage" => coverage = Some(map.next_value()?), - "direction" => direction = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - coverage: coverage.unwrap_or_default(), - direction: direction.unwrap_or_default(), - }) - } - } - d.deserialize_map(CoverManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for CoverMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.coverage.is_some() as usize + self.direction.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.coverage { - map.serialize_entry("coverage", x)?; - } - if let Some(ref x) = self.direction { - map.serialize_entry("direction", x)?; - } - map.end() - } -} -/// Restricted view area. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct FlashlightMania { - pub size_multiplier: Option, - pub combo_based_size: Option, -} -impl FlashlightMania { - /// The acronym of [`FlashlightMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("FL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`FlashlightMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("FI"), - Acronym::from_str_unchecked("HD"), - Acronym::from_str_unchecked("CO"), - ] - } - .into_iter() - } - /// The description of [`FlashlightMania`] - pub const fn description() -> &'static str { - "Restricted view area." - } - /// The [`GameModKind`] of [`FlashlightMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } - /// Bit value of [`FlashlightMania`] - /// - /// See - pub const fn bits() -> u32 { - 1024 - } -} -impl<'de> Deserialize<'de> for FlashlightMania { - fn deserialize>(d: D) -> Result { - struct FlashlightManiaVisitor; - impl<'de> Visitor<'de> for FlashlightManiaVisitor { - type Value = FlashlightMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("FlashlightMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut size_multiplier = None; - let mut combo_based_size = None; - while let Some(key) = map.next_key()? { - match key { - "size_multiplier" => size_multiplier = Some(map.next_value()?), - "combo_based_size" => combo_based_size = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - size_multiplier: size_multiplier.unwrap_or_default(), - combo_based_size: combo_based_size.unwrap_or_default(), - }) - } - } - d.deserialize_map(FlashlightManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for FlashlightMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.size_multiplier.is_some() as usize + self.combo_based_size.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.size_multiplier { - map.serialize_entry("size_multiplier", x)?; - } - if let Some(ref x) = self.combo_based_size { - map.serialize_entry("combo_based_size", x)?; - } - map.end() - } -} -/// Fail if your accuracy drops too low! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct AccuracyChallengeMania { - pub minimum_accuracy: Option, - pub accuracy_judge_mode: Option, - pub restart: Option, -} -impl AccuracyChallengeMania { - /// The acronym of [`AccuracyChallengeMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AC") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AccuracyChallengeMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("CN"), - ] - } - .into_iter() - } - /// The description of [`AccuracyChallengeMania`] - pub const fn description() -> &'static str { - "Fail if your accuracy drops too low!" - } - /// The [`GameModKind`] of [`AccuracyChallengeMania`] - pub const fn kind() -> GameModKind { - GameModKind::DifficultyIncrease - } -} -impl<'de> Deserialize<'de> for AccuracyChallengeMania { - fn deserialize>(d: D) -> Result { - struct AccuracyChallengeManiaVisitor; - impl<'de> Visitor<'de> for AccuracyChallengeManiaVisitor { - type Value = AccuracyChallengeMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AccuracyChallengeMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut minimum_accuracy = None; - let mut accuracy_judge_mode = None; - let mut restart = None; - while let Some(key) = map.next_key()? { - match key { - "minimum_accuracy" => minimum_accuracy = Some(map.next_value()?), - "accuracy_judge_mode" => accuracy_judge_mode = Some(map.next_value()?), - "restart" => restart = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - minimum_accuracy: minimum_accuracy.unwrap_or_default(), - accuracy_judge_mode: accuracy_judge_mode.unwrap_or_default(), - restart: restart.unwrap_or_default(), - }) - } - } - d.deserialize_map(AccuracyChallengeManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AccuracyChallengeMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.minimum_accuracy.is_some() as usize - + self.accuracy_judge_mode.is_some() as usize - + self.restart.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.minimum_accuracy { - map.serialize_entry("minimum_accuracy", x)?; - } - if let Some(ref x) = self.accuracy_judge_mode { - map.serialize_entry("accuracy_judge_mode", x)?; - } - if let Some(ref x) = self.restart { - map.serialize_entry("restart", x)?; - } - map.end() - } -} -/// Shuffle around the keys! -#[derive(Clone, Debug, Default, PartialEq)] -pub struct RandomMania { - pub seed: Option, -} -impl RandomMania { - /// The acronym of [`RandomMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("RD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`RandomMania`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`RandomMania`] - pub const fn description() -> &'static str { - "Shuffle around the keys!" - } - /// The [`GameModKind`] of [`RandomMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`RandomMania`] - /// - /// See - pub const fn bits() -> u32 { - 2097152 - } -} -impl<'de> Deserialize<'de> for RandomMania { - fn deserialize>(d: D) -> Result { - struct RandomManiaVisitor; - impl<'de> Visitor<'de> for RandomManiaVisitor { - type Value = RandomMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("RandomMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut seed = None; - while let Some(key) = map.next_key()? { - match key { - "seed" => seed = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - seed: seed.unwrap_or_default(), - }) - } - } - d.deserialize_map(RandomManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for RandomMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.seed.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.seed { - map.serialize_entry("seed", x)?; - } - map.end() - } -} -/// Double the stages, double the fun! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct DualStagesMania {} -impl DualStagesMania { - /// The acronym of [`DualStagesMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DS") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DualStagesMania`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`DualStagesMania`] - pub const fn description() -> &'static str { - "Double the stages, double the fun!" - } - /// The [`GameModKind`] of [`DualStagesMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`DualStagesMania`] - /// - /// See - pub const fn bits() -> u32 { - 33554432 - } -} -impl<'de> Deserialize<'de> for DualStagesMania { - fn deserialize>(d: D) -> Result { - struct DualStagesManiaVisitor; - impl<'de> Visitor<'de> for DualStagesManiaVisitor { - type Value = DualStagesMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DualStagesMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(DualStagesManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DualStagesMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Notes are flipped horizontally. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct MirrorMania {} -impl MirrorMania { - /// The acronym of [`MirrorMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("MR") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`MirrorMania`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`MirrorMania`] - pub const fn description() -> &'static str { - "Notes are flipped horizontally." - } - /// The [`GameModKind`] of [`MirrorMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`MirrorMania`] - /// - /// See - pub const fn bits() -> u32 { - 1073741824 - } -} -impl<'de> Deserialize<'de> for MirrorMania { - fn deserialize>(d: D) -> Result { - struct MirrorManiaVisitor; - impl<'de> Visitor<'de> for MirrorManiaVisitor { - type Value = MirrorMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("MirrorMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(MirrorManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for MirrorMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Override a beatmap's difficulty settings. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct DifficultyAdjustMania { - pub drain_rate: Option, - pub overall_difficulty: Option, - pub extended_limits: Option, -} -impl DifficultyAdjustMania { - /// The acronym of [`DifficultyAdjustMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("DA") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`DifficultyAdjustMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("EZ"), - Acronym::from_str_unchecked("HR"), - ] - } - .into_iter() - } - /// The description of [`DifficultyAdjustMania`] - pub const fn description() -> &'static str { - "Override a beatmap's difficulty settings." - } - /// The [`GameModKind`] of [`DifficultyAdjustMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for DifficultyAdjustMania { - fn deserialize>(d: D) -> Result { - struct DifficultyAdjustManiaVisitor; - impl<'de> Visitor<'de> for DifficultyAdjustManiaVisitor { - type Value = DifficultyAdjustMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("DifficultyAdjustMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut drain_rate = None; - let mut overall_difficulty = None; - let mut extended_limits = None; - while let Some(key) = map.next_key()? { - match key { - "drain_rate" => drain_rate = Some(map.next_value()?), - "overall_difficulty" => overall_difficulty = Some(map.next_value()?), - "extended_limits" => extended_limits = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - drain_rate: drain_rate.unwrap_or_default(), - overall_difficulty: overall_difficulty.unwrap_or_default(), - extended_limits: extended_limits.unwrap_or_default(), - }) - } - } - d.deserialize_map(DifficultyAdjustManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for DifficultyAdjustMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.drain_rate.is_some() as usize - + self.overall_difficulty.is_some() as usize - + self.extended_limits.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.drain_rate { - map.serialize_entry("drain_rate", x)?; - } - if let Some(ref x) = self.overall_difficulty { - map.serialize_entry("overall_difficulty", x)?; - } - if let Some(ref x) = self.extended_limits { - map.serialize_entry("extended_limits", x)?; - } - map.end() - } -} -/// Feeling nostalgic? -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ClassicMania {} -impl ClassicMania { - /// The acronym of [`ClassicMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CL") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ClassicMania`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`ClassicMania`] - pub const fn description() -> &'static str { - "Feeling nostalgic?" - } - /// The [`GameModKind`] of [`ClassicMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for ClassicMania { - fn deserialize>(d: D) -> Result { - struct ClassicManiaVisitor; - impl<'de> Visitor<'de> for ClassicManiaVisitor { - type Value = ClassicMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ClassicMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ClassicManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ClassicMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Hold the keys. To the beat. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct InvertMania {} -impl InvertMania { - /// The acronym of [`InvertMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("IN") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`InvertMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("HO")] }.into_iter() - } - /// The description of [`InvertMania`] - pub const fn description() -> &'static str { - "Hold the keys. To the beat." - } - /// The [`GameModKind`] of [`InvertMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for InvertMania { - fn deserialize>(d: D) -> Result { - struct InvertManiaVisitor; - impl<'de> Visitor<'de> for InvertManiaVisitor { - type Value = InvertMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("InvertMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(InvertManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for InvertMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// No more tricky speed changes! -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ConstantSpeedMania {} -impl ConstantSpeedMania { - /// The acronym of [`ConstantSpeedMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CS") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ConstantSpeedMania`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`ConstantSpeedMania`] - pub const fn description() -> &'static str { - "No more tricky speed changes!" - } - /// The [`GameModKind`] of [`ConstantSpeedMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for ConstantSpeedMania { - fn deserialize>(d: D) -> Result { - struct ConstantSpeedManiaVisitor; - impl<'de> Visitor<'de> for ConstantSpeedManiaVisitor { - type Value = ConstantSpeedMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ConstantSpeedMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ConstantSpeedManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ConstantSpeedMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Replaces all hold notes with normal notes. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct HoldOffMania {} -impl HoldOffMania { - /// The acronym of [`HoldOffMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("HO") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`HoldOffMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { [Acronym::from_str_unchecked("IN")] }.into_iter() - } - /// The description of [`HoldOffMania`] - pub const fn description() -> &'static str { - "Replaces all hold notes with normal notes." - } - /// The [`GameModKind`] of [`HoldOffMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for HoldOffMania { - fn deserialize>(d: D) -> Result { - struct HoldOffManiaVisitor; - impl<'de> Visitor<'de> for HoldOffManiaVisitor { - type Value = HoldOffMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("HoldOffMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(HoldOffManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for HoldOffMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with one key. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct OneKeyMania {} -impl OneKeyMania { - /// The acronym of [`OneKeyMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("1K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`OneKeyMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("2K"), - Acronym::from_str_unchecked("3K"), - Acronym::from_str_unchecked("4K"), - Acronym::from_str_unchecked("5K"), - Acronym::from_str_unchecked("6K"), - Acronym::from_str_unchecked("7K"), - Acronym::from_str_unchecked("8K"), - Acronym::from_str_unchecked("9K"), - Acronym::from_str_unchecked("10K"), - ] - } - .into_iter() - } - /// The description of [`OneKeyMania`] - pub const fn description() -> &'static str { - "Play with one key." - } - /// The [`GameModKind`] of [`OneKeyMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`OneKeyMania`] - /// - /// See - pub const fn bits() -> u32 { - 67108864 - } -} -impl<'de> Deserialize<'de> for OneKeyMania { - fn deserialize>(d: D) -> Result { - struct OneKeyManiaVisitor; - impl<'de> Visitor<'de> for OneKeyManiaVisitor { - type Value = OneKeyMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("OneKeyMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(OneKeyManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for OneKeyMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with two keys. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct TwoKeysMania {} -impl TwoKeysMania { - /// The acronym of [`TwoKeysMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("2K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`TwoKeysMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("1K"), - Acronym::from_str_unchecked("3K"), - Acronym::from_str_unchecked("4K"), - Acronym::from_str_unchecked("5K"), - Acronym::from_str_unchecked("6K"), - Acronym::from_str_unchecked("7K"), - Acronym::from_str_unchecked("8K"), - Acronym::from_str_unchecked("9K"), - Acronym::from_str_unchecked("10K"), - ] - } - .into_iter() - } - /// The description of [`TwoKeysMania`] - pub const fn description() -> &'static str { - "Play with two keys." - } - /// The [`GameModKind`] of [`TwoKeysMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`TwoKeysMania`] - /// - /// See - pub const fn bits() -> u32 { - 268435456 - } -} -impl<'de> Deserialize<'de> for TwoKeysMania { - fn deserialize>(d: D) -> Result { - struct TwoKeysManiaVisitor; - impl<'de> Visitor<'de> for TwoKeysManiaVisitor { - type Value = TwoKeysMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("TwoKeysMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(TwoKeysManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for TwoKeysMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with three keys. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ThreeKeysMania {} -impl ThreeKeysMania { - /// The acronym of [`ThreeKeysMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("3K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ThreeKeysMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("1K"), - Acronym::from_str_unchecked("2K"), - Acronym::from_str_unchecked("4K"), - Acronym::from_str_unchecked("5K"), - Acronym::from_str_unchecked("6K"), - Acronym::from_str_unchecked("7K"), - Acronym::from_str_unchecked("8K"), - Acronym::from_str_unchecked("9K"), - Acronym::from_str_unchecked("10K"), - ] - } - .into_iter() - } - /// The description of [`ThreeKeysMania`] - pub const fn description() -> &'static str { - "Play with three keys." - } - /// The [`GameModKind`] of [`ThreeKeysMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`ThreeKeysMania`] - /// - /// See - pub const fn bits() -> u32 { - 134217728 - } -} -impl<'de> Deserialize<'de> for ThreeKeysMania { - fn deserialize>(d: D) -> Result { - struct ThreeKeysManiaVisitor; - impl<'de> Visitor<'de> for ThreeKeysManiaVisitor { - type Value = ThreeKeysMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ThreeKeysMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ThreeKeysManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ThreeKeysMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with four keys. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct FourKeysMania {} -impl FourKeysMania { - /// The acronym of [`FourKeysMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("4K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`FourKeysMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("1K"), - Acronym::from_str_unchecked("2K"), - Acronym::from_str_unchecked("3K"), - Acronym::from_str_unchecked("5K"), - Acronym::from_str_unchecked("6K"), - Acronym::from_str_unchecked("7K"), - Acronym::from_str_unchecked("8K"), - Acronym::from_str_unchecked("9K"), - Acronym::from_str_unchecked("10K"), - ] - } - .into_iter() - } - /// The description of [`FourKeysMania`] - pub const fn description() -> &'static str { - "Play with four keys." - } - /// The [`GameModKind`] of [`FourKeysMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`FourKeysMania`] - /// - /// See - pub const fn bits() -> u32 { - 32768 - } -} -impl<'de> Deserialize<'de> for FourKeysMania { - fn deserialize>(d: D) -> Result { - struct FourKeysManiaVisitor; - impl<'de> Visitor<'de> for FourKeysManiaVisitor { - type Value = FourKeysMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("FourKeysMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(FourKeysManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for FourKeysMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with five keys. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct FiveKeysMania {} -impl FiveKeysMania { - /// The acronym of [`FiveKeysMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("5K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`FiveKeysMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("1K"), - Acronym::from_str_unchecked("2K"), - Acronym::from_str_unchecked("3K"), - Acronym::from_str_unchecked("4K"), - Acronym::from_str_unchecked("6K"), - Acronym::from_str_unchecked("7K"), - Acronym::from_str_unchecked("8K"), - Acronym::from_str_unchecked("9K"), - Acronym::from_str_unchecked("10K"), - ] - } - .into_iter() - } - /// The description of [`FiveKeysMania`] - pub const fn description() -> &'static str { - "Play with five keys." - } - /// The [`GameModKind`] of [`FiveKeysMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`FiveKeysMania`] - /// - /// See - pub const fn bits() -> u32 { - 65536 - } -} -impl<'de> Deserialize<'de> for FiveKeysMania { - fn deserialize>(d: D) -> Result { - struct FiveKeysManiaVisitor; - impl<'de> Visitor<'de> for FiveKeysManiaVisitor { - type Value = FiveKeysMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("FiveKeysMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(FiveKeysManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for FiveKeysMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with six keys. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct SixKeysMania {} -impl SixKeysMania { - /// The acronym of [`SixKeysMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("6K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SixKeysMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("1K"), - Acronym::from_str_unchecked("2K"), - Acronym::from_str_unchecked("3K"), - Acronym::from_str_unchecked("4K"), - Acronym::from_str_unchecked("5K"), - Acronym::from_str_unchecked("7K"), - Acronym::from_str_unchecked("8K"), - Acronym::from_str_unchecked("9K"), - Acronym::from_str_unchecked("10K"), - ] - } - .into_iter() - } - /// The description of [`SixKeysMania`] - pub const fn description() -> &'static str { - "Play with six keys." - } - /// The [`GameModKind`] of [`SixKeysMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`SixKeysMania`] - /// - /// See - pub const fn bits() -> u32 { - 131072 - } -} -impl<'de> Deserialize<'de> for SixKeysMania { - fn deserialize>(d: D) -> Result { - struct SixKeysManiaVisitor; - impl<'de> Visitor<'de> for SixKeysManiaVisitor { - type Value = SixKeysMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SixKeysMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(SixKeysManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SixKeysMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with seven keys. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct SevenKeysMania {} -impl SevenKeysMania { - /// The acronym of [`SevenKeysMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("7K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`SevenKeysMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("1K"), - Acronym::from_str_unchecked("2K"), - Acronym::from_str_unchecked("3K"), - Acronym::from_str_unchecked("4K"), - Acronym::from_str_unchecked("5K"), - Acronym::from_str_unchecked("6K"), - Acronym::from_str_unchecked("8K"), - Acronym::from_str_unchecked("9K"), - Acronym::from_str_unchecked("10K"), - ] - } - .into_iter() - } - /// The description of [`SevenKeysMania`] - pub const fn description() -> &'static str { - "Play with seven keys." - } - /// The [`GameModKind`] of [`SevenKeysMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`SevenKeysMania`] - /// - /// See - pub const fn bits() -> u32 { - 262144 - } -} -impl<'de> Deserialize<'de> for SevenKeysMania { - fn deserialize>(d: D) -> Result { - struct SevenKeysManiaVisitor; - impl<'de> Visitor<'de> for SevenKeysManiaVisitor { - type Value = SevenKeysMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("SevenKeysMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(SevenKeysManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for SevenKeysMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with eight keys. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct EightKeysMania {} -impl EightKeysMania { - /// The acronym of [`EightKeysMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("8K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`EightKeysMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("1K"), - Acronym::from_str_unchecked("2K"), - Acronym::from_str_unchecked("3K"), - Acronym::from_str_unchecked("4K"), - Acronym::from_str_unchecked("5K"), - Acronym::from_str_unchecked("6K"), - Acronym::from_str_unchecked("7K"), - Acronym::from_str_unchecked("9K"), - Acronym::from_str_unchecked("10K"), - ] - } - .into_iter() - } - /// The description of [`EightKeysMania`] - pub const fn description() -> &'static str { - "Play with eight keys." - } - /// The [`GameModKind`] of [`EightKeysMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`EightKeysMania`] - /// - /// See - pub const fn bits() -> u32 { - 524288 - } -} -impl<'de> Deserialize<'de> for EightKeysMania { - fn deserialize>(d: D) -> Result { - struct EightKeysManiaVisitor; - impl<'de> Visitor<'de> for EightKeysManiaVisitor { - type Value = EightKeysMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("EightKeysMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(EightKeysManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for EightKeysMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with nine keys. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct NineKeysMania {} -impl NineKeysMania { - /// The acronym of [`NineKeysMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("9K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`NineKeysMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("1K"), - Acronym::from_str_unchecked("2K"), - Acronym::from_str_unchecked("3K"), - Acronym::from_str_unchecked("4K"), - Acronym::from_str_unchecked("5K"), - Acronym::from_str_unchecked("6K"), - Acronym::from_str_unchecked("7K"), - Acronym::from_str_unchecked("8K"), - Acronym::from_str_unchecked("10K"), - ] - } - .into_iter() - } - /// The description of [`NineKeysMania`] - pub const fn description() -> &'static str { - "Play with nine keys." - } - /// The [`GameModKind`] of [`NineKeysMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } - /// Bit value of [`NineKeysMania`] - /// - /// See - pub const fn bits() -> u32 { - 16777216 - } -} -impl<'de> Deserialize<'de> for NineKeysMania { - fn deserialize>(d: D) -> Result { - struct NineKeysManiaVisitor; - impl<'de> Visitor<'de> for NineKeysManiaVisitor { - type Value = NineKeysMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("NineKeysMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(NineKeysManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for NineKeysMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Play with ten keys. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct TenKeysMania {} -impl TenKeysMania { - /// The acronym of [`TenKeysMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("10K") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`TenKeysMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("1K"), - Acronym::from_str_unchecked("2K"), - Acronym::from_str_unchecked("3K"), - Acronym::from_str_unchecked("4K"), - Acronym::from_str_unchecked("5K"), - Acronym::from_str_unchecked("6K"), - Acronym::from_str_unchecked("7K"), - Acronym::from_str_unchecked("8K"), - Acronym::from_str_unchecked("9K"), - ] - } - .into_iter() - } - /// The description of [`TenKeysMania`] - pub const fn description() -> &'static str { - "Play with ten keys." - } - /// The [`GameModKind`] of [`TenKeysMania`] - pub const fn kind() -> GameModKind { - GameModKind::Conversion - } -} -impl<'de> Deserialize<'de> for TenKeysMania { - fn deserialize>(d: D) -> Result { - struct TenKeysManiaVisitor; - impl<'de> Visitor<'de> for TenKeysManiaVisitor { - type Value = TenKeysMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("TenKeysMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(TenKeysManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for TenKeysMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Watch a perfect automated play through the song. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct AutoplayMania {} -impl AutoplayMania { - /// The acronym of [`AutoplayMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AT") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AutoplayMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`AutoplayMania`] - pub const fn description() -> &'static str { - "Watch a perfect automated play through the song." - } - /// The [`GameModKind`] of [`AutoplayMania`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`AutoplayMania`] - /// - /// See - pub const fn bits() -> u32 { - 2048 - } -} -impl<'de> Deserialize<'de> for AutoplayMania { - fn deserialize>(d: D) -> Result { - struct AutoplayManiaVisitor; - impl<'de> Visitor<'de> for AutoplayManiaVisitor { - type Value = AutoplayMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AutoplayMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(AutoplayManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AutoplayMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Watch the video without visual distractions. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct CinemaMania {} -impl CinemaMania { - /// The acronym of [`CinemaMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("CN") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`CinemaMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("NF"), - Acronym::from_str_unchecked("SD"), - Acronym::from_str_unchecked("PF"), - Acronym::from_str_unchecked("AC"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`CinemaMania`] - pub const fn description() -> &'static str { - "Watch the video without visual distractions." - } - /// The [`GameModKind`] of [`CinemaMania`] - pub const fn kind() -> GameModKind { - GameModKind::Automation - } - /// Bit value of [`CinemaMania`] - /// - /// See - pub const fn bits() -> u32 { - 4194304 - } -} -impl<'de> Deserialize<'de> for CinemaMania { - fn deserialize>(d: D) -> Result { - struct CinemaManiaVisitor; - impl<'de> Visitor<'de> for CinemaManiaVisitor { - type Value = CinemaMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("CinemaMania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(CinemaManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for CinemaMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Can you keep up? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct WindUpMania { - pub initial_rate: Option, - pub final_rate: Option, - pub adjust_pitch: Option, -} -impl WindUpMania { - /// The acronym of [`WindUpMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("WU") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`WindUpMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WD"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`WindUpMania`] - pub const fn description() -> &'static str { - "Can you keep up?" - } - /// The [`GameModKind`] of [`WindUpMania`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for WindUpMania { - fn deserialize>(d: D) -> Result { - struct WindUpManiaVisitor; - impl<'de> Visitor<'de> for WindUpManiaVisitor { - type Value = WindUpMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("WindUpMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut final_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "final_rate" => final_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - final_rate: final_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(WindUpManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for WindUpMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.initial_rate.is_some() as usize - + self.final_rate.is_some() as usize - + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.final_rate { - map.serialize_entry("final_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Sloooow doooown... -#[derive(Clone, Debug, Default, PartialEq)] -pub struct WindDownMania { - pub initial_rate: Option, - pub final_rate: Option, - pub adjust_pitch: Option, -} -impl WindDownMania { - /// The acronym of [`WindDownMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("WD") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`WindDownMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("AS"), - ] - } - .into_iter() - } - /// The description of [`WindDownMania`] - pub const fn description() -> &'static str { - "Sloooow doooown..." - } - /// The [`GameModKind`] of [`WindDownMania`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for WindDownMania { - fn deserialize>(d: D) -> Result { - struct WindDownManiaVisitor; - impl<'de> Visitor<'de> for WindDownManiaVisitor { - type Value = WindDownMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("WindDownMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut final_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "final_rate" => final_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - final_rate: final_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(WindDownManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for WindDownMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.initial_rate.is_some() as usize - + self.final_rate.is_some() as usize - + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.final_rate { - map.serialize_entry("final_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Can you still feel the rhythm without music? -#[derive(Clone, Debug, Default, PartialEq)] -pub struct MutedMania { - pub inverse_muting: Option, - pub enable_metronome: Option, - pub mute_combo_count: Option, - pub affects_hit_sounds: Option, -} -impl MutedMania { - /// The acronym of [`MutedMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("MU") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`MutedMania`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`MutedMania`] - pub const fn description() -> &'static str { - "Can you still feel the rhythm without music?" - } - /// The [`GameModKind`] of [`MutedMania`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for MutedMania { - fn deserialize>(d: D) -> Result { - struct MutedManiaVisitor; - impl<'de> Visitor<'de> for MutedManiaVisitor { - type Value = MutedMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("MutedMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut inverse_muting = None; - let mut enable_metronome = None; - let mut mute_combo_count = None; - let mut affects_hit_sounds = None; - while let Some(key) = map.next_key()? { - match key { - "inverse_muting" => inverse_muting = Some(map.next_value()?), - "enable_metronome" => enable_metronome = Some(map.next_value()?), - "mute_combo_count" => mute_combo_count = Some(map.next_value()?), - "affects_hit_sounds" => affects_hit_sounds = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - inverse_muting: inverse_muting.unwrap_or_default(), - enable_metronome: enable_metronome.unwrap_or_default(), - mute_combo_count: mute_combo_count.unwrap_or_default(), - affects_hit_sounds: affects_hit_sounds.unwrap_or_default(), - }) - } - } - d.deserialize_map(MutedManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for MutedMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = self.inverse_muting.is_some() as usize - + self.enable_metronome.is_some() as usize - + self.mute_combo_count.is_some() as usize - + self.affects_hit_sounds.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.inverse_muting { - map.serialize_entry("inverse_muting", x)?; - } - if let Some(ref x) = self.enable_metronome { - map.serialize_entry("enable_metronome", x)?; - } - if let Some(ref x) = self.mute_combo_count { - map.serialize_entry("mute_combo_count", x)?; - } - if let Some(ref x) = self.affects_hit_sounds { - map.serialize_entry("affects_hit_sounds", x)?; - } - map.end() - } -} -/// Let track speed adapt to you. -#[derive(Clone, Debug, Default, PartialEq)] -pub struct AdaptiveSpeedMania { - pub initial_rate: Option, - pub adjust_pitch: Option, -} -impl AdaptiveSpeedMania { - /// The acronym of [`AdaptiveSpeedMania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("AS") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`AdaptiveSpeedMania`] - pub fn incompatible_mods() -> impl Iterator { - unsafe { - [ - Acronym::from_str_unchecked("HT"), - Acronym::from_str_unchecked("DC"), - Acronym::from_str_unchecked("DT"), - Acronym::from_str_unchecked("NC"), - Acronym::from_str_unchecked("AT"), - Acronym::from_str_unchecked("CN"), - Acronym::from_str_unchecked("WU"), - Acronym::from_str_unchecked("WD"), - ] - } - .into_iter() - } - /// The description of [`AdaptiveSpeedMania`] - pub const fn description() -> &'static str { - "Let track speed adapt to you." - } - /// The [`GameModKind`] of [`AdaptiveSpeedMania`] - pub const fn kind() -> GameModKind { - GameModKind::Fun - } -} -impl<'de> Deserialize<'de> for AdaptiveSpeedMania { - fn deserialize>(d: D) -> Result { - struct AdaptiveSpeedManiaVisitor; - impl<'de> Visitor<'de> for AdaptiveSpeedManiaVisitor { - type Value = AdaptiveSpeedMania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("AdaptiveSpeedMania") - } - fn visit_map>(self, mut map: A) -> Result { - let mut initial_rate = None; - let mut adjust_pitch = None; - while let Some(key) = map.next_key()? { - match key { - "initial_rate" => initial_rate = Some(map.next_value()?), - "adjust_pitch" => adjust_pitch = Some(map.next_value()?), - _ => { - let _: IgnoredAny = map.next_value()?; - } - } - } - Ok(Self::Value { - initial_rate: initial_rate.unwrap_or_default(), - adjust_pitch: adjust_pitch.unwrap_or_default(), - }) - } - } - d.deserialize_map(AdaptiveSpeedManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for AdaptiveSpeedMania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = - self.initial_rate.is_some() as usize + self.adjust_pitch.is_some() as usize; - let mut map = s.serialize_map(Some(field_count))?; - if let Some(ref x) = self.initial_rate { - map.serialize_entry("initial_rate", x)?; - } - if let Some(ref x) = self.adjust_pitch { - map.serialize_entry("adjust_pitch", x)?; - } - map.end() - } -} -/// Score set on earlier osu! versions with the V2 scoring algorithm active. -#[derive(Copy, Eq, Clone, Debug, Default, PartialEq)] -pub struct ScoreV2Mania {} -impl ScoreV2Mania { - /// The acronym of [`ScoreV2Mania`] - pub const fn acronym() -> Acronym { - unsafe { Acronym::from_str_unchecked("SV2") } - } - /// Iterator of [`Acronym`] for mods that are incompatible with [`ScoreV2Mania`] - pub fn incompatible_mods() -> impl Iterator { - [].into_iter() - } - /// The description of [`ScoreV2Mania`] - pub const fn description() -> &'static str { - "Score set on earlier osu! versions with the V2 scoring algorithm active." - } - /// The [`GameModKind`] of [`ScoreV2Mania`] - pub const fn kind() -> GameModKind { - GameModKind::System - } - /// Bit value of [`ScoreV2Mania`] - /// - /// See - pub const fn bits() -> u32 { - 536870912 - } -} -impl<'de> Deserialize<'de> for ScoreV2Mania { - fn deserialize>(d: D) -> Result { - struct ScoreV2ManiaVisitor; - impl<'de> Visitor<'de> for ScoreV2ManiaVisitor { - type Value = ScoreV2Mania; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("ScoreV2Mania") - } - fn visit_map>(self, _: A) -> Result { - Ok(Self::Value {}) - } - } - d.deserialize_map(ScoreV2ManiaVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for ScoreV2Mania { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let field_count = 0; - let map = s.serialize_map(Some(field_count))?; - map.end() - } -} -/// Any mod unknown to `rosu-v2` -#[derive(Copy, Eq, Clone, Debug, PartialEq, PartialOrd, Ord, Hash)] -pub struct UnknownMod { - pub acronym: Acronym, -} -impl UnknownMod { - /// The default [`Acronym`] for an unknown mod without specific - /// acronym. - pub const UNKNOWN_ACRONYM: Acronym = unsafe { Acronym::from_str_unchecked("??") }; - /// A custom [`Acronym`] for any unknown mod - pub const fn acronym(self) -> Acronym { - self.acronym - } - /// Returns an empty iterator - pub const fn incompatible_mods() -> std::iter::Empty { - std::iter::empty() - } - /// A custom description for any unknown mod - pub const fn description() -> &'static str { - "Any mod unknown to the rosu-v2 crate" - } - /// A manually assigned [`GameModKind`] for any unknown mod - pub const fn kind() -> GameModKind { - GameModKind::System - } -} -impl Default for UnknownMod { - fn default() -> Self { - Self { - acronym: Self::UNKNOWN_ACRONYM, - } - } -} -impl<'de> Deserialize<'de> for UnknownMod { - fn deserialize>(d: D) -> Result { - struct UnknownModVisitor; - impl<'de> Visitor<'de> for UnknownModVisitor { - type Value = UnknownMod; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("any unknown mod") - } - fn visit_map>(self, mut map: A) -> Result { - while map.next_entry::()?.is_some() {} - Ok(UnknownMod { - acronym: UnknownMod::UNKNOWN_ACRONYM, - }) - } - } - d.deserialize_map(UnknownModVisitor) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for UnknownMod { - fn serialize(&self, s: S) -> Result { - s.serialize_map(Some(0)) - .and_then(serde::ser::SerializeMap::end) - } -} -/// The different types of a [`GameMod`] -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize))] -pub enum GameModKind { - DifficultyReduction, - DifficultyIncrease, - Conversion, - Automation, - Fun, - System, -} -/// The kind of a [`GameMod`] when the mode is ignored -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub enum GameModIntermode { - AccuracyChallenge, - AdaptiveSpeed, - Alternate, - ApproachDifferent, - Autopilot, - Autoplay, - BarrelRoll, - Blinds, - Bubbles, - Cinema, - Classic, - ConstantSpeed, - Cover, - Daycore, - Deflate, - Depth, - DifficultyAdjust, - DoubleTime, - DualStages, - Easy, - EightKeys, - FadeIn, - FiveKeys, - Flashlight, - FloatingFruits, - FourKeys, - FreezeFrame, - Grow, - HalfTime, - HardRock, - Hidden, - HoldOff, - Invert, - Magnetised, - Mirror, - Muted, - Nightcore, - NineKeys, - NoFail, - NoScope, - OneKey, - Perfect, - Random, - Relax, - Repel, - ScoreV2, - SevenKeys, - SingleTap, - SixKeys, - SpinIn, - SpunOut, - StrictTracking, - SuddenDeath, - Swap, - Synesthesia, - TargetPractice, - TenKeys, - ThreeKeys, - TouchDevice, - Traceable, - Transform, - TwoKeys, - Wiggle, - WindDown, - WindUp, - Unknown(UnknownMod), -} -impl GameModIntermode { - /// The [`Acronym`] of this [`GameModIntermode`] - pub const fn acronym(&self) -> Acronym { - unsafe { - match self { - Self::AccuracyChallenge => Acronym::from_str_unchecked("AC"), - Self::AdaptiveSpeed => Acronym::from_str_unchecked("AS"), - Self::Alternate => Acronym::from_str_unchecked("AL"), - Self::ApproachDifferent => Acronym::from_str_unchecked("AD"), - Self::Autopilot => Acronym::from_str_unchecked("AP"), - Self::Autoplay => Acronym::from_str_unchecked("AT"), - Self::BarrelRoll => Acronym::from_str_unchecked("BR"), - Self::Blinds => Acronym::from_str_unchecked("BL"), - Self::Bubbles => Acronym::from_str_unchecked("BU"), - Self::Cinema => Acronym::from_str_unchecked("CN"), - Self::Classic => Acronym::from_str_unchecked("CL"), - Self::ConstantSpeed => Acronym::from_str_unchecked("CS"), - Self::Cover => Acronym::from_str_unchecked("CO"), - Self::Daycore => Acronym::from_str_unchecked("DC"), - Self::Deflate => Acronym::from_str_unchecked("DF"), - Self::Depth => Acronym::from_str_unchecked("DP"), - Self::DifficultyAdjust => Acronym::from_str_unchecked("DA"), - Self::DoubleTime => Acronym::from_str_unchecked("DT"), - Self::DualStages => Acronym::from_str_unchecked("DS"), - Self::Easy => Acronym::from_str_unchecked("EZ"), - Self::EightKeys => Acronym::from_str_unchecked("8K"), - Self::FadeIn => Acronym::from_str_unchecked("FI"), - Self::FiveKeys => Acronym::from_str_unchecked("5K"), - Self::Flashlight => Acronym::from_str_unchecked("FL"), - Self::FloatingFruits => Acronym::from_str_unchecked("FF"), - Self::FourKeys => Acronym::from_str_unchecked("4K"), - Self::FreezeFrame => Acronym::from_str_unchecked("FR"), - Self::Grow => Acronym::from_str_unchecked("GR"), - Self::HalfTime => Acronym::from_str_unchecked("HT"), - Self::HardRock => Acronym::from_str_unchecked("HR"), - Self::Hidden => Acronym::from_str_unchecked("HD"), - Self::HoldOff => Acronym::from_str_unchecked("HO"), - Self::Invert => Acronym::from_str_unchecked("IN"), - Self::Magnetised => Acronym::from_str_unchecked("MG"), - Self::Mirror => Acronym::from_str_unchecked("MR"), - Self::Muted => Acronym::from_str_unchecked("MU"), - Self::Nightcore => Acronym::from_str_unchecked("NC"), - Self::NineKeys => Acronym::from_str_unchecked("9K"), - Self::NoFail => Acronym::from_str_unchecked("NF"), - Self::NoScope => Acronym::from_str_unchecked("NS"), - Self::OneKey => Acronym::from_str_unchecked("1K"), - Self::Perfect => Acronym::from_str_unchecked("PF"), - Self::Random => Acronym::from_str_unchecked("RD"), - Self::Relax => Acronym::from_str_unchecked("RX"), - Self::Repel => Acronym::from_str_unchecked("RP"), - Self::ScoreV2 => Acronym::from_str_unchecked("SV2"), - Self::SevenKeys => Acronym::from_str_unchecked("7K"), - Self::SingleTap => Acronym::from_str_unchecked("SG"), - Self::SixKeys => Acronym::from_str_unchecked("6K"), - Self::SpinIn => Acronym::from_str_unchecked("SI"), - Self::SpunOut => Acronym::from_str_unchecked("SO"), - Self::StrictTracking => Acronym::from_str_unchecked("ST"), - Self::SuddenDeath => Acronym::from_str_unchecked("SD"), - Self::Swap => Acronym::from_str_unchecked("SW"), - Self::Synesthesia => Acronym::from_str_unchecked("SY"), - Self::TargetPractice => Acronym::from_str_unchecked("TP"), - Self::TenKeys => Acronym::from_str_unchecked("10K"), - Self::ThreeKeys => Acronym::from_str_unchecked("3K"), - Self::TouchDevice => Acronym::from_str_unchecked("TD"), - Self::Traceable => Acronym::from_str_unchecked("TC"), - Self::Transform => Acronym::from_str_unchecked("TR"), - Self::TwoKeys => Acronym::from_str_unchecked("2K"), - Self::Wiggle => Acronym::from_str_unchecked("WG"), - Self::WindDown => Acronym::from_str_unchecked("WD"), - Self::WindUp => Acronym::from_str_unchecked("WU"), - Self::Unknown(m) => m.acronym(), - } - } - } - /// Bit value of the [`GameModIntermode`] - /// - /// See - pub const fn bits(self) -> Option { - match self { - Self::AccuracyChallenge => None, - Self::AdaptiveSpeed => None, - Self::Alternate => None, - Self::ApproachDifferent => None, - Self::Autopilot => Some(8192), - Self::Autoplay => Some(2048), - Self::BarrelRoll => None, - Self::Blinds => None, - Self::Bubbles => None, - Self::Cinema => Some(4194304), - Self::Classic => None, - Self::ConstantSpeed => None, - Self::Cover => None, - Self::Daycore => None, - Self::Deflate => None, - Self::Depth => None, - Self::DifficultyAdjust => None, - Self::DoubleTime => Some(64), - Self::DualStages => Some(33554432), - Self::Easy => Some(2), - Self::EightKeys => Some(524288), - Self::FadeIn => Some(1048576), - Self::FiveKeys => Some(65536), - Self::Flashlight => Some(1024), - Self::FloatingFruits => None, - Self::FourKeys => Some(32768), - Self::FreezeFrame => None, - Self::Grow => None, - Self::HalfTime => Some(256), - Self::HardRock => Some(16), - Self::Hidden => Some(8), - Self::HoldOff => None, - Self::Invert => None, - Self::Magnetised => None, - Self::Mirror => Some(1073741824), - Self::Muted => None, - Self::Nightcore => Some(576), - Self::NineKeys => Some(16777216), - Self::NoFail => Some(1), - Self::NoScope => None, - Self::OneKey => Some(67108864), - Self::Perfect => Some(16416), - Self::Random => Some(2097152), - Self::Relax => Some(128), - Self::Repel => None, - Self::ScoreV2 => Some(536870912), - Self::SevenKeys => Some(262144), - Self::SingleTap => None, - Self::SixKeys => Some(131072), - Self::SpinIn => None, - Self::SpunOut => Some(4096), - Self::StrictTracking => None, - Self::SuddenDeath => Some(32), - Self::Swap => None, - Self::Synesthesia => None, - Self::TargetPractice => Some(8388608), - Self::TenKeys => None, - Self::ThreeKeys => Some(134217728), - Self::TouchDevice => Some(4), - Self::Traceable => None, - Self::Transform => None, - Self::TwoKeys => Some(268435456), - Self::Wiggle => None, - Self::WindDown => None, - Self::WindUp => None, - Self::Unknown(_) => None, - } - } - /// The [`GameModKind`] of this [`GameModIntermode`] - pub const fn kind(&self) -> GameModKind { - match self { - Self::AccuracyChallenge => GameModKind::DifficultyIncrease, - Self::AdaptiveSpeed => GameModKind::Fun, - Self::Alternate => GameModKind::Conversion, - Self::ApproachDifferent => GameModKind::Fun, - Self::Autopilot => GameModKind::Automation, - Self::Autoplay => GameModKind::Automation, - Self::BarrelRoll => GameModKind::Fun, - Self::Blinds => GameModKind::DifficultyIncrease, - Self::Bubbles => GameModKind::Fun, - Self::Cinema => GameModKind::Automation, - Self::Classic => GameModKind::Conversion, - Self::ConstantSpeed => GameModKind::Conversion, - Self::Cover => GameModKind::DifficultyIncrease, - Self::Daycore => GameModKind::DifficultyReduction, - Self::Deflate => GameModKind::Fun, - Self::Depth => GameModKind::Fun, - Self::DifficultyAdjust => GameModKind::Conversion, - Self::DoubleTime => GameModKind::DifficultyIncrease, - Self::DualStages => GameModKind::Conversion, - Self::Easy => GameModKind::DifficultyReduction, - Self::EightKeys => GameModKind::Conversion, - Self::FadeIn => GameModKind::DifficultyIncrease, - Self::FiveKeys => GameModKind::Conversion, - Self::Flashlight => GameModKind::DifficultyIncrease, - Self::FloatingFruits => GameModKind::Fun, - Self::FourKeys => GameModKind::Conversion, - Self::FreezeFrame => GameModKind::Fun, - Self::Grow => GameModKind::Fun, - Self::HalfTime => GameModKind::DifficultyReduction, - Self::HardRock => GameModKind::DifficultyIncrease, - Self::Hidden => GameModKind::DifficultyIncrease, - Self::HoldOff => GameModKind::Conversion, - Self::Invert => GameModKind::Conversion, - Self::Magnetised => GameModKind::Fun, - Self::Mirror => GameModKind::Conversion, - Self::Muted => GameModKind::Fun, - Self::Nightcore => GameModKind::DifficultyIncrease, - Self::NineKeys => GameModKind::Conversion, - Self::NoFail => GameModKind::DifficultyReduction, - Self::NoScope => GameModKind::Fun, - Self::OneKey => GameModKind::Conversion, - Self::Perfect => GameModKind::DifficultyIncrease, - Self::Random => GameModKind::Conversion, - Self::Relax => GameModKind::Automation, - Self::Repel => GameModKind::Fun, - Self::ScoreV2 => GameModKind::System, - Self::SevenKeys => GameModKind::Conversion, - Self::SingleTap => GameModKind::Conversion, - Self::SixKeys => GameModKind::Conversion, - Self::SpinIn => GameModKind::Fun, - Self::SpunOut => GameModKind::Automation, - Self::StrictTracking => GameModKind::DifficultyIncrease, - Self::SuddenDeath => GameModKind::DifficultyIncrease, - Self::Swap => GameModKind::Conversion, - Self::Synesthesia => GameModKind::Fun, - Self::TargetPractice => GameModKind::Conversion, - Self::TenKeys => GameModKind::Conversion, - Self::ThreeKeys => GameModKind::Conversion, - Self::TouchDevice => GameModKind::System, - Self::Traceable => GameModKind::Fun, - Self::Transform => GameModKind::Fun, - Self::TwoKeys => GameModKind::Conversion, - Self::Wiggle => GameModKind::Fun, - Self::WindDown => GameModKind::Fun, - Self::WindUp => GameModKind::Fun, - Self::Unknown(_) => GameModKind::System, - } - } - /// Parse an [`Acronym`] into a [`GameModIntermode`] - pub fn from_acronym(acronym: Acronym) -> Self { - match acronym.as_str() { - "AC" => Self::AccuracyChallenge, - "AS" => Self::AdaptiveSpeed, - "AL" => Self::Alternate, - "AD" => Self::ApproachDifferent, - "AP" => Self::Autopilot, - "AT" => Self::Autoplay, - "BR" => Self::BarrelRoll, - "BL" => Self::Blinds, - "BU" => Self::Bubbles, - "CN" => Self::Cinema, - "CL" => Self::Classic, - "CS" => Self::ConstantSpeed, - "CO" => Self::Cover, - "DC" => Self::Daycore, - "DF" => Self::Deflate, - "DP" => Self::Depth, - "DA" => Self::DifficultyAdjust, - "DT" => Self::DoubleTime, - "DS" => Self::DualStages, - "EZ" => Self::Easy, - "8K" => Self::EightKeys, - "FI" => Self::FadeIn, - "5K" => Self::FiveKeys, - "FL" => Self::Flashlight, - "FF" => Self::FloatingFruits, - "4K" => Self::FourKeys, - "FR" => Self::FreezeFrame, - "GR" => Self::Grow, - "HT" => Self::HalfTime, - "HR" => Self::HardRock, - "HD" => Self::Hidden, - "HO" => Self::HoldOff, - "IN" => Self::Invert, - "MG" => Self::Magnetised, - "MR" => Self::Mirror, - "MU" => Self::Muted, - "NC" => Self::Nightcore, - "9K" => Self::NineKeys, - "NF" => Self::NoFail, - "NS" => Self::NoScope, - "1K" => Self::OneKey, - "PF" => Self::Perfect, - "RD" => Self::Random, - "RX" => Self::Relax, - "RP" => Self::Repel, - "SV2" => Self::ScoreV2, - "7K" => Self::SevenKeys, - "SG" => Self::SingleTap, - "6K" => Self::SixKeys, - "SI" => Self::SpinIn, - "SO" => Self::SpunOut, - "ST" => Self::StrictTracking, - "SD" => Self::SuddenDeath, - "SW" => Self::Swap, - "SY" => Self::Synesthesia, - "TP" => Self::TargetPractice, - "10K" => Self::TenKeys, - "3K" => Self::ThreeKeys, - "TD" => Self::TouchDevice, - "TC" => Self::Traceable, - "TR" => Self::Transform, - "2K" => Self::TwoKeys, - "WG" => Self::Wiggle, - "WD" => Self::WindDown, - "WU" => Self::WindUp, - _ => Self::Unknown(UnknownMod { acronym }), - } - } -} -impl PartialOrd for GameModIntermode { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl Ord for GameModIntermode { - fn cmp(&self, other: &Self) -> Ordering { - match (self.bits(), other.bits()) { - (Some(self_bits), Some(other_bits)) => self_bits.cmp(&other_bits), - (Some(_), None) => Ordering::Less, - (None, Some(_)) => Ordering::Greater, - (None, None) => self.acronym().as_str().cmp(other.acronym().as_str()), - } - } -} -impl Display for GameModIntermode { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str(self.acronym().as_str()) - } -} -impl From<&GameModIntermode> for GameModIntermode { - fn from(gamemod: &GameModIntermode) -> Self { - *gamemod - } -} -impl From for GameModIntermode { - fn from(gamemod: GameMod) -> Self { - gamemod.intermode() - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for GameModIntermode { - fn serialize(&self, s: S) -> Result { - s.serialize_str(self.acronym().as_str()) - } -} -#[derive(Copy, Clone, PartialEq, Eq)] -pub(crate) struct GameModOrder { - mode: GameMode, - index: Option, - intermode: GameModIntermode, -} -impl From<&GameMod> for GameModOrder { - fn from(gamemod: &GameMod) -> Self { - const fn inner(gamemod: &GameMod) -> GameModOrder { - macro_rules! arm { - ($mode:ident, $gamemod:ident, Some($discriminant:literal), $intermode:ident) => { - arm!( - $mode, - $gamemod, - Some(unsafe { NonZeroU8::new_unchecked($discriminant) }), - $intermode, - ) - }; - ($mode:ident, $gamemod:ident, $index:expr, $intermode:ident $(,)?) => { - GameModOrder { - mode: GameMode::$mode, - index: $index, - intermode: GameModIntermode::$intermode, - } - }; - } - match gamemod { - GameMod::EasyOsu(_) => arm!(Osu, EasyOsu, Some(2), Easy), - GameMod::NoFailOsu(_) => arm!(Osu, NoFailOsu, Some(1), NoFail), - GameMod::HalfTimeOsu(_) => arm!(Osu, HalfTimeOsu, Some(9), HalfTime), - GameMod::DaycoreOsu(_) => arm!(Osu, DaycoreOsu, None, Daycore), - GameMod::HardRockOsu(_) => arm!(Osu, HardRockOsu, Some(5), HardRock), - GameMod::SuddenDeathOsu(_) => arm!(Osu, SuddenDeathOsu, Some(6), SuddenDeath), - GameMod::PerfectOsu(_) => arm!(Osu, PerfectOsu, Some(15), Perfect), - GameMod::DoubleTimeOsu(_) => arm!(Osu, DoubleTimeOsu, Some(7), DoubleTime), - GameMod::NightcoreOsu(_) => arm!(Osu, NightcoreOsu, Some(10), Nightcore), - GameMod::HiddenOsu(_) => arm!(Osu, HiddenOsu, Some(4), Hidden), - GameMod::FlashlightOsu(_) => arm!(Osu, FlashlightOsu, Some(11), Flashlight), - GameMod::BlindsOsu(_) => arm!(Osu, BlindsOsu, None, Blinds), - GameMod::StrictTrackingOsu(_) => arm!(Osu, StrictTrackingOsu, None, StrictTracking), - GameMod::AccuracyChallengeOsu(_) => { - arm!(Osu, AccuracyChallengeOsu, None, AccuracyChallenge) - } - GameMod::TargetPracticeOsu(_) => { - arm!(Osu, TargetPracticeOsu, Some(24), TargetPractice) - } - GameMod::DifficultyAdjustOsu(_) => { - arm!(Osu, DifficultyAdjustOsu, None, DifficultyAdjust) - } - GameMod::ClassicOsu(_) => arm!(Osu, ClassicOsu, None, Classic), - GameMod::RandomOsu(_) => arm!(Osu, RandomOsu, Some(22), Random), - GameMod::MirrorOsu(_) => arm!(Osu, MirrorOsu, Some(31), Mirror), - GameMod::AlternateOsu(_) => arm!(Osu, AlternateOsu, None, Alternate), - GameMod::SingleTapOsu(_) => arm!(Osu, SingleTapOsu, None, SingleTap), - GameMod::AutoplayOsu(_) => arm!(Osu, AutoplayOsu, Some(12), Autoplay), - GameMod::CinemaOsu(_) => arm!(Osu, CinemaOsu, Some(23), Cinema), - GameMod::RelaxOsu(_) => arm!(Osu, RelaxOsu, Some(8), Relax), - GameMod::AutopilotOsu(_) => arm!(Osu, AutopilotOsu, Some(14), Autopilot), - GameMod::SpunOutOsu(_) => arm!(Osu, SpunOutOsu, Some(13), SpunOut), - GameMod::TransformOsu(_) => arm!(Osu, TransformOsu, None, Transform), - GameMod::WiggleOsu(_) => arm!(Osu, WiggleOsu, None, Wiggle), - GameMod::SpinInOsu(_) => arm!(Osu, SpinInOsu, None, SpinIn), - GameMod::GrowOsu(_) => arm!(Osu, GrowOsu, None, Grow), - GameMod::DeflateOsu(_) => arm!(Osu, DeflateOsu, None, Deflate), - GameMod::WindUpOsu(_) => arm!(Osu, WindUpOsu, None, WindUp), - GameMod::WindDownOsu(_) => arm!(Osu, WindDownOsu, None, WindDown), - GameMod::TraceableOsu(_) => arm!(Osu, TraceableOsu, None, Traceable), - GameMod::BarrelRollOsu(_) => arm!(Osu, BarrelRollOsu, None, BarrelRoll), - GameMod::ApproachDifferentOsu(_) => { - arm!(Osu, ApproachDifferentOsu, None, ApproachDifferent) - } - GameMod::MutedOsu(_) => arm!(Osu, MutedOsu, None, Muted), - GameMod::NoScopeOsu(_) => arm!(Osu, NoScopeOsu, None, NoScope), - GameMod::MagnetisedOsu(_) => arm!(Osu, MagnetisedOsu, None, Magnetised), - GameMod::RepelOsu(_) => arm!(Osu, RepelOsu, None, Repel), - GameMod::AdaptiveSpeedOsu(_) => arm!(Osu, AdaptiveSpeedOsu, None, AdaptiveSpeed), - GameMod::FreezeFrameOsu(_) => arm!(Osu, FreezeFrameOsu, None, FreezeFrame), - GameMod::BubblesOsu(_) => arm!(Osu, BubblesOsu, None, Bubbles), - GameMod::SynesthesiaOsu(_) => arm!(Osu, SynesthesiaOsu, None, Synesthesia), - GameMod::DepthOsu(_) => arm!(Osu, DepthOsu, None, Depth), - GameMod::TouchDeviceOsu(_) => arm!(Osu, TouchDeviceOsu, Some(3), TouchDevice), - GameMod::ScoreV2Osu(_) => arm!(Osu, ScoreV2Osu, Some(30), ScoreV2), - GameMod::UnknownOsu(m) => GameModOrder { - mode: GameMode::Osu, - index: None, - intermode: GameModIntermode::Unknown(*m), - }, - GameMod::EasyTaiko(_) => arm!(Taiko, EasyTaiko, Some(2), Easy), - GameMod::NoFailTaiko(_) => arm!(Taiko, NoFailTaiko, Some(1), NoFail), - GameMod::HalfTimeTaiko(_) => arm!(Taiko, HalfTimeTaiko, Some(9), HalfTime), - GameMod::DaycoreTaiko(_) => arm!(Taiko, DaycoreTaiko, None, Daycore), - GameMod::HardRockTaiko(_) => arm!(Taiko, HardRockTaiko, Some(5), HardRock), - GameMod::SuddenDeathTaiko(_) => arm!(Taiko, SuddenDeathTaiko, Some(6), SuddenDeath), - GameMod::PerfectTaiko(_) => arm!(Taiko, PerfectTaiko, Some(15), Perfect), - GameMod::DoubleTimeTaiko(_) => arm!(Taiko, DoubleTimeTaiko, Some(7), DoubleTime), - GameMod::NightcoreTaiko(_) => arm!(Taiko, NightcoreTaiko, Some(10), Nightcore), - GameMod::HiddenTaiko(_) => arm!(Taiko, HiddenTaiko, Some(4), Hidden), - GameMod::FlashlightTaiko(_) => arm!(Taiko, FlashlightTaiko, Some(11), Flashlight), - GameMod::AccuracyChallengeTaiko(_) => { - arm!(Taiko, AccuracyChallengeTaiko, None, AccuracyChallenge) - } - GameMod::RandomTaiko(_) => arm!(Taiko, RandomTaiko, Some(22), Random), - GameMod::DifficultyAdjustTaiko(_) => { - arm!(Taiko, DifficultyAdjustTaiko, None, DifficultyAdjust) - } - GameMod::ClassicTaiko(_) => arm!(Taiko, ClassicTaiko, None, Classic), - GameMod::SwapTaiko(_) => arm!(Taiko, SwapTaiko, None, Swap), - GameMod::SingleTapTaiko(_) => arm!(Taiko, SingleTapTaiko, None, SingleTap), - GameMod::ConstantSpeedTaiko(_) => { - arm!(Taiko, ConstantSpeedTaiko, None, ConstantSpeed) - } - GameMod::AutoplayTaiko(_) => arm!(Taiko, AutoplayTaiko, Some(12), Autoplay), - GameMod::CinemaTaiko(_) => arm!(Taiko, CinemaTaiko, Some(23), Cinema), - GameMod::RelaxTaiko(_) => arm!(Taiko, RelaxTaiko, Some(8), Relax), - GameMod::WindUpTaiko(_) => arm!(Taiko, WindUpTaiko, None, WindUp), - GameMod::WindDownTaiko(_) => arm!(Taiko, WindDownTaiko, None, WindDown), - GameMod::MutedTaiko(_) => arm!(Taiko, MutedTaiko, None, Muted), - GameMod::AdaptiveSpeedTaiko(_) => { - arm!(Taiko, AdaptiveSpeedTaiko, None, AdaptiveSpeed) - } - GameMod::ScoreV2Taiko(_) => arm!(Taiko, ScoreV2Taiko, Some(30), ScoreV2), - GameMod::UnknownTaiko(m) => GameModOrder { - mode: GameMode::Taiko, - index: None, - intermode: GameModIntermode::Unknown(*m), - }, - GameMod::EasyCatch(_) => arm!(Catch, EasyCatch, Some(2), Easy), - GameMod::NoFailCatch(_) => arm!(Catch, NoFailCatch, Some(1), NoFail), - GameMod::HalfTimeCatch(_) => arm!(Catch, HalfTimeCatch, Some(9), HalfTime), - GameMod::DaycoreCatch(_) => arm!(Catch, DaycoreCatch, None, Daycore), - GameMod::HardRockCatch(_) => arm!(Catch, HardRockCatch, Some(5), HardRock), - GameMod::SuddenDeathCatch(_) => arm!(Catch, SuddenDeathCatch, Some(6), SuddenDeath), - GameMod::PerfectCatch(_) => arm!(Catch, PerfectCatch, Some(15), Perfect), - GameMod::DoubleTimeCatch(_) => arm!(Catch, DoubleTimeCatch, Some(7), DoubleTime), - GameMod::NightcoreCatch(_) => arm!(Catch, NightcoreCatch, Some(10), Nightcore), - GameMod::HiddenCatch(_) => arm!(Catch, HiddenCatch, Some(4), Hidden), - GameMod::FlashlightCatch(_) => arm!(Catch, FlashlightCatch, Some(11), Flashlight), - GameMod::AccuracyChallengeCatch(_) => { - arm!(Catch, AccuracyChallengeCatch, None, AccuracyChallenge) - } - GameMod::DifficultyAdjustCatch(_) => { - arm!(Catch, DifficultyAdjustCatch, None, DifficultyAdjust) - } - GameMod::ClassicCatch(_) => arm!(Catch, ClassicCatch, None, Classic), - GameMod::MirrorCatch(_) => arm!(Catch, MirrorCatch, Some(31), Mirror), - GameMod::AutoplayCatch(_) => arm!(Catch, AutoplayCatch, Some(12), Autoplay), - GameMod::CinemaCatch(_) => arm!(Catch, CinemaCatch, Some(23), Cinema), - GameMod::RelaxCatch(_) => arm!(Catch, RelaxCatch, Some(8), Relax), - GameMod::WindUpCatch(_) => arm!(Catch, WindUpCatch, None, WindUp), - GameMod::WindDownCatch(_) => arm!(Catch, WindDownCatch, None, WindDown), - GameMod::FloatingFruitsCatch(_) => { - arm!(Catch, FloatingFruitsCatch, None, FloatingFruits) - } - GameMod::MutedCatch(_) => arm!(Catch, MutedCatch, None, Muted), - GameMod::NoScopeCatch(_) => arm!(Catch, NoScopeCatch, None, NoScope), - GameMod::ScoreV2Catch(_) => arm!(Catch, ScoreV2Catch, Some(30), ScoreV2), - GameMod::UnknownCatch(m) => GameModOrder { - mode: GameMode::Catch, - index: None, - intermode: GameModIntermode::Unknown(*m), - }, - GameMod::EasyMania(_) => arm!(Mania, EasyMania, Some(2), Easy), - GameMod::NoFailMania(_) => arm!(Mania, NoFailMania, Some(1), NoFail), - GameMod::HalfTimeMania(_) => arm!(Mania, HalfTimeMania, Some(9), HalfTime), - GameMod::DaycoreMania(_) => arm!(Mania, DaycoreMania, None, Daycore), - GameMod::HardRockMania(_) => arm!(Mania, HardRockMania, Some(5), HardRock), - GameMod::SuddenDeathMania(_) => arm!(Mania, SuddenDeathMania, Some(6), SuddenDeath), - GameMod::PerfectMania(_) => arm!(Mania, PerfectMania, Some(15), Perfect), - GameMod::DoubleTimeMania(_) => arm!(Mania, DoubleTimeMania, Some(7), DoubleTime), - GameMod::NightcoreMania(_) => arm!(Mania, NightcoreMania, Some(10), Nightcore), - GameMod::FadeInMania(_) => arm!(Mania, FadeInMania, Some(21), FadeIn), - GameMod::HiddenMania(_) => arm!(Mania, HiddenMania, Some(4), Hidden), - GameMod::CoverMania(_) => arm!(Mania, CoverMania, None, Cover), - GameMod::FlashlightMania(_) => arm!(Mania, FlashlightMania, Some(11), Flashlight), - GameMod::AccuracyChallengeMania(_) => { - arm!(Mania, AccuracyChallengeMania, None, AccuracyChallenge) - } - GameMod::RandomMania(_) => arm!(Mania, RandomMania, Some(22), Random), - GameMod::DualStagesMania(_) => arm!(Mania, DualStagesMania, Some(26), DualStages), - GameMod::MirrorMania(_) => arm!(Mania, MirrorMania, Some(31), Mirror), - GameMod::DifficultyAdjustMania(_) => { - arm!(Mania, DifficultyAdjustMania, None, DifficultyAdjust) - } - GameMod::ClassicMania(_) => arm!(Mania, ClassicMania, None, Classic), - GameMod::InvertMania(_) => arm!(Mania, InvertMania, None, Invert), - GameMod::ConstantSpeedMania(_) => { - arm!(Mania, ConstantSpeedMania, None, ConstantSpeed) - } - GameMod::HoldOffMania(_) => arm!(Mania, HoldOffMania, None, HoldOff), - GameMod::OneKeyMania(_) => arm!(Mania, OneKeyMania, Some(27), OneKey), - GameMod::TwoKeysMania(_) => arm!(Mania, TwoKeysMania, Some(29), TwoKeys), - GameMod::ThreeKeysMania(_) => arm!(Mania, ThreeKeysMania, Some(28), ThreeKeys), - GameMod::FourKeysMania(_) => arm!(Mania, FourKeysMania, Some(16), FourKeys), - GameMod::FiveKeysMania(_) => arm!(Mania, FiveKeysMania, Some(17), FiveKeys), - GameMod::SixKeysMania(_) => arm!(Mania, SixKeysMania, Some(18), SixKeys), - GameMod::SevenKeysMania(_) => arm!(Mania, SevenKeysMania, Some(19), SevenKeys), - GameMod::EightKeysMania(_) => arm!(Mania, EightKeysMania, Some(20), EightKeys), - GameMod::NineKeysMania(_) => arm!(Mania, NineKeysMania, Some(25), NineKeys), - GameMod::TenKeysMania(_) => arm!(Mania, TenKeysMania, None, TenKeys), - GameMod::AutoplayMania(_) => arm!(Mania, AutoplayMania, Some(12), Autoplay), - GameMod::CinemaMania(_) => arm!(Mania, CinemaMania, Some(23), Cinema), - GameMod::WindUpMania(_) => arm!(Mania, WindUpMania, None, WindUp), - GameMod::WindDownMania(_) => arm!(Mania, WindDownMania, None, WindDown), - GameMod::MutedMania(_) => arm!(Mania, MutedMania, None, Muted), - GameMod::AdaptiveSpeedMania(_) => { - arm!(Mania, AdaptiveSpeedMania, None, AdaptiveSpeed) - } - GameMod::ScoreV2Mania(_) => arm!(Mania, ScoreV2Mania, Some(30), ScoreV2), - GameMod::UnknownMania(m) => GameModOrder { - mode: GameMode::Mania, - index: None, - intermode: GameModIntermode::Unknown(*m), - }, - } - } - inner(gamemod) - } -} -impl PartialOrd for GameModOrder { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl Ord for GameModOrder { - fn cmp(&self, other: &Self) -> Ordering { - self.mode - .cmp(&other.mode) - .then_with(|| match (self.index, other.index) { - (Some(self_idx), Some(other_idx)) => self_idx.cmp(&other_idx), - (Some(_), None) => Ordering::Less, - (None, Some(_)) => Ordering::Greater, - (None, None) => self - .intermode - .acronym() - .as_str() - .cmp(other.intermode.acronym().as_str()), - }) - } -} -impl PartialEq for GameModOrder { - fn eq(&self, other: &GameModIntermode) -> bool { - self.intermode.eq(other) - } -} -impl Borrow for GameModOrder { - fn borrow(&self) -> &GameModIntermode { - &self.intermode - } -} -/// A single game mod -#[derive(Clone, Debug, PartialEq)] -#[non_exhaustive] -pub enum GameMod { - EasyOsu(EasyOsu), - NoFailOsu(NoFailOsu), - HalfTimeOsu(HalfTimeOsu), - DaycoreOsu(DaycoreOsu), - HardRockOsu(HardRockOsu), - SuddenDeathOsu(SuddenDeathOsu), - PerfectOsu(PerfectOsu), - DoubleTimeOsu(DoubleTimeOsu), - NightcoreOsu(NightcoreOsu), - HiddenOsu(HiddenOsu), - FlashlightOsu(FlashlightOsu), - BlindsOsu(BlindsOsu), - StrictTrackingOsu(StrictTrackingOsu), - AccuracyChallengeOsu(AccuracyChallengeOsu), - TargetPracticeOsu(TargetPracticeOsu), - DifficultyAdjustOsu(DifficultyAdjustOsu), - ClassicOsu(ClassicOsu), - RandomOsu(RandomOsu), - MirrorOsu(MirrorOsu), - AlternateOsu(AlternateOsu), - SingleTapOsu(SingleTapOsu), - AutoplayOsu(AutoplayOsu), - CinemaOsu(CinemaOsu), - RelaxOsu(RelaxOsu), - AutopilotOsu(AutopilotOsu), - SpunOutOsu(SpunOutOsu), - TransformOsu(TransformOsu), - WiggleOsu(WiggleOsu), - SpinInOsu(SpinInOsu), - GrowOsu(GrowOsu), - DeflateOsu(DeflateOsu), - WindUpOsu(WindUpOsu), - WindDownOsu(WindDownOsu), - TraceableOsu(TraceableOsu), - BarrelRollOsu(BarrelRollOsu), - ApproachDifferentOsu(ApproachDifferentOsu), - MutedOsu(MutedOsu), - NoScopeOsu(NoScopeOsu), - MagnetisedOsu(MagnetisedOsu), - RepelOsu(RepelOsu), - AdaptiveSpeedOsu(AdaptiveSpeedOsu), - FreezeFrameOsu(FreezeFrameOsu), - BubblesOsu(BubblesOsu), - SynesthesiaOsu(SynesthesiaOsu), - DepthOsu(DepthOsu), - TouchDeviceOsu(TouchDeviceOsu), - ScoreV2Osu(ScoreV2Osu), - UnknownOsu(UnknownMod), - EasyTaiko(EasyTaiko), - NoFailTaiko(NoFailTaiko), - HalfTimeTaiko(HalfTimeTaiko), - DaycoreTaiko(DaycoreTaiko), - HardRockTaiko(HardRockTaiko), - SuddenDeathTaiko(SuddenDeathTaiko), - PerfectTaiko(PerfectTaiko), - DoubleTimeTaiko(DoubleTimeTaiko), - NightcoreTaiko(NightcoreTaiko), - HiddenTaiko(HiddenTaiko), - FlashlightTaiko(FlashlightTaiko), - AccuracyChallengeTaiko(AccuracyChallengeTaiko), - RandomTaiko(RandomTaiko), - DifficultyAdjustTaiko(DifficultyAdjustTaiko), - ClassicTaiko(ClassicTaiko), - SwapTaiko(SwapTaiko), - SingleTapTaiko(SingleTapTaiko), - ConstantSpeedTaiko(ConstantSpeedTaiko), - AutoplayTaiko(AutoplayTaiko), - CinemaTaiko(CinemaTaiko), - RelaxTaiko(RelaxTaiko), - WindUpTaiko(WindUpTaiko), - WindDownTaiko(WindDownTaiko), - MutedTaiko(MutedTaiko), - AdaptiveSpeedTaiko(AdaptiveSpeedTaiko), - ScoreV2Taiko(ScoreV2Taiko), - UnknownTaiko(UnknownMod), - EasyCatch(EasyCatch), - NoFailCatch(NoFailCatch), - HalfTimeCatch(HalfTimeCatch), - DaycoreCatch(DaycoreCatch), - HardRockCatch(HardRockCatch), - SuddenDeathCatch(SuddenDeathCatch), - PerfectCatch(PerfectCatch), - DoubleTimeCatch(DoubleTimeCatch), - NightcoreCatch(NightcoreCatch), - HiddenCatch(HiddenCatch), - FlashlightCatch(FlashlightCatch), - AccuracyChallengeCatch(AccuracyChallengeCatch), - DifficultyAdjustCatch(DifficultyAdjustCatch), - ClassicCatch(ClassicCatch), - MirrorCatch(MirrorCatch), - AutoplayCatch(AutoplayCatch), - CinemaCatch(CinemaCatch), - RelaxCatch(RelaxCatch), - WindUpCatch(WindUpCatch), - WindDownCatch(WindDownCatch), - FloatingFruitsCatch(FloatingFruitsCatch), - MutedCatch(MutedCatch), - NoScopeCatch(NoScopeCatch), - ScoreV2Catch(ScoreV2Catch), - UnknownCatch(UnknownMod), - EasyMania(EasyMania), - NoFailMania(NoFailMania), - HalfTimeMania(HalfTimeMania), - DaycoreMania(DaycoreMania), - HardRockMania(HardRockMania), - SuddenDeathMania(SuddenDeathMania), - PerfectMania(PerfectMania), - DoubleTimeMania(DoubleTimeMania), - NightcoreMania(NightcoreMania), - FadeInMania(FadeInMania), - HiddenMania(HiddenMania), - CoverMania(CoverMania), - FlashlightMania(FlashlightMania), - AccuracyChallengeMania(AccuracyChallengeMania), - RandomMania(RandomMania), - DualStagesMania(DualStagesMania), - MirrorMania(MirrorMania), - DifficultyAdjustMania(DifficultyAdjustMania), - ClassicMania(ClassicMania), - InvertMania(InvertMania), - ConstantSpeedMania(ConstantSpeedMania), - HoldOffMania(HoldOffMania), - OneKeyMania(OneKeyMania), - TwoKeysMania(TwoKeysMania), - ThreeKeysMania(ThreeKeysMania), - FourKeysMania(FourKeysMania), - FiveKeysMania(FiveKeysMania), - SixKeysMania(SixKeysMania), - SevenKeysMania(SevenKeysMania), - EightKeysMania(EightKeysMania), - NineKeysMania(NineKeysMania), - TenKeysMania(TenKeysMania), - AutoplayMania(AutoplayMania), - CinemaMania(CinemaMania), - WindUpMania(WindUpMania), - WindDownMania(WindDownMania), - MutedMania(MutedMania), - AdaptiveSpeedMania(AdaptiveSpeedMania), - ScoreV2Mania(ScoreV2Mania), - UnknownMania(UnknownMod), -} -impl GameMod { - /// Create a new [`GameMod`] - pub fn new(acronym: &str, mode: GameMode) -> Self { - match (acronym, mode) { - ("EZ", GameMode::Osu) => Self::EasyOsu(Default::default()), - ("NF", GameMode::Osu) => Self::NoFailOsu(Default::default()), - ("HT", GameMode::Osu) => Self::HalfTimeOsu(Default::default()), - ("DC", GameMode::Osu) => Self::DaycoreOsu(Default::default()), - ("HR", GameMode::Osu) => Self::HardRockOsu(Default::default()), - ("SD", GameMode::Osu) => Self::SuddenDeathOsu(Default::default()), - ("PF", GameMode::Osu) => Self::PerfectOsu(Default::default()), - ("DT", GameMode::Osu) => Self::DoubleTimeOsu(Default::default()), - ("NC", GameMode::Osu) => Self::NightcoreOsu(Default::default()), - ("HD", GameMode::Osu) => Self::HiddenOsu(Default::default()), - ("FL", GameMode::Osu) => Self::FlashlightOsu(Default::default()), - ("BL", GameMode::Osu) => Self::BlindsOsu(Default::default()), - ("ST", GameMode::Osu) => Self::StrictTrackingOsu(Default::default()), - ("AC", GameMode::Osu) => Self::AccuracyChallengeOsu(Default::default()), - ("TP", GameMode::Osu) => Self::TargetPracticeOsu(Default::default()), - ("DA", GameMode::Osu) => Self::DifficultyAdjustOsu(Default::default()), - ("CL", GameMode::Osu) => Self::ClassicOsu(Default::default()), - ("RD", GameMode::Osu) => Self::RandomOsu(Default::default()), - ("MR", GameMode::Osu) => Self::MirrorOsu(Default::default()), - ("AL", GameMode::Osu) => Self::AlternateOsu(Default::default()), - ("SG", GameMode::Osu) => Self::SingleTapOsu(Default::default()), - ("AT", GameMode::Osu) => Self::AutoplayOsu(Default::default()), - ("CN", GameMode::Osu) => Self::CinemaOsu(Default::default()), - ("RX", GameMode::Osu) => Self::RelaxOsu(Default::default()), - ("AP", GameMode::Osu) => Self::AutopilotOsu(Default::default()), - ("SO", GameMode::Osu) => Self::SpunOutOsu(Default::default()), - ("TR", GameMode::Osu) => Self::TransformOsu(Default::default()), - ("WG", GameMode::Osu) => Self::WiggleOsu(Default::default()), - ("SI", GameMode::Osu) => Self::SpinInOsu(Default::default()), - ("GR", GameMode::Osu) => Self::GrowOsu(Default::default()), - ("DF", GameMode::Osu) => Self::DeflateOsu(Default::default()), - ("WU", GameMode::Osu) => Self::WindUpOsu(Default::default()), - ("WD", GameMode::Osu) => Self::WindDownOsu(Default::default()), - ("TC", GameMode::Osu) => Self::TraceableOsu(Default::default()), - ("BR", GameMode::Osu) => Self::BarrelRollOsu(Default::default()), - ("AD", GameMode::Osu) => Self::ApproachDifferentOsu(Default::default()), - ("MU", GameMode::Osu) => Self::MutedOsu(Default::default()), - ("NS", GameMode::Osu) => Self::NoScopeOsu(Default::default()), - ("MG", GameMode::Osu) => Self::MagnetisedOsu(Default::default()), - ("RP", GameMode::Osu) => Self::RepelOsu(Default::default()), - ("AS", GameMode::Osu) => Self::AdaptiveSpeedOsu(Default::default()), - ("FR", GameMode::Osu) => Self::FreezeFrameOsu(Default::default()), - ("BU", GameMode::Osu) => Self::BubblesOsu(Default::default()), - ("SY", GameMode::Osu) => Self::SynesthesiaOsu(Default::default()), - ("DP", GameMode::Osu) => Self::DepthOsu(Default::default()), - ("TD", GameMode::Osu) => Self::TouchDeviceOsu(Default::default()), - ("SV2", GameMode::Osu) => Self::ScoreV2Osu(Default::default()), - ("EZ", GameMode::Taiko) => Self::EasyTaiko(Default::default()), - ("NF", GameMode::Taiko) => Self::NoFailTaiko(Default::default()), - ("HT", GameMode::Taiko) => Self::HalfTimeTaiko(Default::default()), - ("DC", GameMode::Taiko) => Self::DaycoreTaiko(Default::default()), - ("HR", GameMode::Taiko) => Self::HardRockTaiko(Default::default()), - ("SD", GameMode::Taiko) => Self::SuddenDeathTaiko(Default::default()), - ("PF", GameMode::Taiko) => Self::PerfectTaiko(Default::default()), - ("DT", GameMode::Taiko) => Self::DoubleTimeTaiko(Default::default()), - ("NC", GameMode::Taiko) => Self::NightcoreTaiko(Default::default()), - ("HD", GameMode::Taiko) => Self::HiddenTaiko(Default::default()), - ("FL", GameMode::Taiko) => Self::FlashlightTaiko(Default::default()), - ("AC", GameMode::Taiko) => Self::AccuracyChallengeTaiko(Default::default()), - ("RD", GameMode::Taiko) => Self::RandomTaiko(Default::default()), - ("DA", GameMode::Taiko) => Self::DifficultyAdjustTaiko(Default::default()), - ("CL", GameMode::Taiko) => Self::ClassicTaiko(Default::default()), - ("SW", GameMode::Taiko) => Self::SwapTaiko(Default::default()), - ("SG", GameMode::Taiko) => Self::SingleTapTaiko(Default::default()), - ("CS", GameMode::Taiko) => Self::ConstantSpeedTaiko(Default::default()), - ("AT", GameMode::Taiko) => Self::AutoplayTaiko(Default::default()), - ("CN", GameMode::Taiko) => Self::CinemaTaiko(Default::default()), - ("RX", GameMode::Taiko) => Self::RelaxTaiko(Default::default()), - ("WU", GameMode::Taiko) => Self::WindUpTaiko(Default::default()), - ("WD", GameMode::Taiko) => Self::WindDownTaiko(Default::default()), - ("MU", GameMode::Taiko) => Self::MutedTaiko(Default::default()), - ("AS", GameMode::Taiko) => Self::AdaptiveSpeedTaiko(Default::default()), - ("SV2", GameMode::Taiko) => Self::ScoreV2Taiko(Default::default()), - ("EZ", GameMode::Catch) => Self::EasyCatch(Default::default()), - ("NF", GameMode::Catch) => Self::NoFailCatch(Default::default()), - ("HT", GameMode::Catch) => Self::HalfTimeCatch(Default::default()), - ("DC", GameMode::Catch) => Self::DaycoreCatch(Default::default()), - ("HR", GameMode::Catch) => Self::HardRockCatch(Default::default()), - ("SD", GameMode::Catch) => Self::SuddenDeathCatch(Default::default()), - ("PF", GameMode::Catch) => Self::PerfectCatch(Default::default()), - ("DT", GameMode::Catch) => Self::DoubleTimeCatch(Default::default()), - ("NC", GameMode::Catch) => Self::NightcoreCatch(Default::default()), - ("HD", GameMode::Catch) => Self::HiddenCatch(Default::default()), - ("FL", GameMode::Catch) => Self::FlashlightCatch(Default::default()), - ("AC", GameMode::Catch) => Self::AccuracyChallengeCatch(Default::default()), - ("DA", GameMode::Catch) => Self::DifficultyAdjustCatch(Default::default()), - ("CL", GameMode::Catch) => Self::ClassicCatch(Default::default()), - ("MR", GameMode::Catch) => Self::MirrorCatch(Default::default()), - ("AT", GameMode::Catch) => Self::AutoplayCatch(Default::default()), - ("CN", GameMode::Catch) => Self::CinemaCatch(Default::default()), - ("RX", GameMode::Catch) => Self::RelaxCatch(Default::default()), - ("WU", GameMode::Catch) => Self::WindUpCatch(Default::default()), - ("WD", GameMode::Catch) => Self::WindDownCatch(Default::default()), - ("FF", GameMode::Catch) => Self::FloatingFruitsCatch(Default::default()), - ("MU", GameMode::Catch) => Self::MutedCatch(Default::default()), - ("NS", GameMode::Catch) => Self::NoScopeCatch(Default::default()), - ("SV2", GameMode::Catch) => Self::ScoreV2Catch(Default::default()), - ("EZ", GameMode::Mania) => Self::EasyMania(Default::default()), - ("NF", GameMode::Mania) => Self::NoFailMania(Default::default()), - ("HT", GameMode::Mania) => Self::HalfTimeMania(Default::default()), - ("DC", GameMode::Mania) => Self::DaycoreMania(Default::default()), - ("HR", GameMode::Mania) => Self::HardRockMania(Default::default()), - ("SD", GameMode::Mania) => Self::SuddenDeathMania(Default::default()), - ("PF", GameMode::Mania) => Self::PerfectMania(Default::default()), - ("DT", GameMode::Mania) => Self::DoubleTimeMania(Default::default()), - ("NC", GameMode::Mania) => Self::NightcoreMania(Default::default()), - ("FI", GameMode::Mania) => Self::FadeInMania(Default::default()), - ("HD", GameMode::Mania) => Self::HiddenMania(Default::default()), - ("CO", GameMode::Mania) => Self::CoverMania(Default::default()), - ("FL", GameMode::Mania) => Self::FlashlightMania(Default::default()), - ("AC", GameMode::Mania) => Self::AccuracyChallengeMania(Default::default()), - ("RD", GameMode::Mania) => Self::RandomMania(Default::default()), - ("DS", GameMode::Mania) => Self::DualStagesMania(Default::default()), - ("MR", GameMode::Mania) => Self::MirrorMania(Default::default()), - ("DA", GameMode::Mania) => Self::DifficultyAdjustMania(Default::default()), - ("CL", GameMode::Mania) => Self::ClassicMania(Default::default()), - ("IN", GameMode::Mania) => Self::InvertMania(Default::default()), - ("CS", GameMode::Mania) => Self::ConstantSpeedMania(Default::default()), - ("HO", GameMode::Mania) => Self::HoldOffMania(Default::default()), - ("1K", GameMode::Mania) => Self::OneKeyMania(Default::default()), - ("2K", GameMode::Mania) => Self::TwoKeysMania(Default::default()), - ("3K", GameMode::Mania) => Self::ThreeKeysMania(Default::default()), - ("4K", GameMode::Mania) => Self::FourKeysMania(Default::default()), - ("5K", GameMode::Mania) => Self::FiveKeysMania(Default::default()), - ("6K", GameMode::Mania) => Self::SixKeysMania(Default::default()), - ("7K", GameMode::Mania) => Self::SevenKeysMania(Default::default()), - ("8K", GameMode::Mania) => Self::EightKeysMania(Default::default()), - ("9K", GameMode::Mania) => Self::NineKeysMania(Default::default()), - ("10K", GameMode::Mania) => Self::TenKeysMania(Default::default()), - ("AT", GameMode::Mania) => Self::AutoplayMania(Default::default()), - ("CN", GameMode::Mania) => Self::CinemaMania(Default::default()), - ("WU", GameMode::Mania) => Self::WindUpMania(Default::default()), - ("WD", GameMode::Mania) => Self::WindDownMania(Default::default()), - ("MU", GameMode::Mania) => Self::MutedMania(Default::default()), - ("AS", GameMode::Mania) => Self::AdaptiveSpeedMania(Default::default()), - ("SV2", GameMode::Mania) => Self::ScoreV2Mania(Default::default()), - _ => { - let acronym = ::from_str(acronym) - .unwrap_or(UnknownMod::UNKNOWN_ACRONYM); - let unknown = UnknownMod { acronym }; - match mode { - GameMode::Osu => GameMod::UnknownOsu(unknown), - GameMode::Taiko => GameMod::UnknownTaiko(unknown), - GameMode::Catch => GameMod::UnknownCatch(unknown), - GameMode::Mania => GameMod::UnknownMania(unknown), - } - } - } - } - /// The acronym of this [`GameMod`] - pub const fn acronym(&self) -> Acronym { - match self { - Self::EasyOsu(_) => EasyOsu::acronym(), - Self::NoFailOsu(_) => NoFailOsu::acronym(), - Self::HalfTimeOsu(_) => HalfTimeOsu::acronym(), - Self::DaycoreOsu(_) => DaycoreOsu::acronym(), - Self::HardRockOsu(_) => HardRockOsu::acronym(), - Self::SuddenDeathOsu(_) => SuddenDeathOsu::acronym(), - Self::PerfectOsu(_) => PerfectOsu::acronym(), - Self::DoubleTimeOsu(_) => DoubleTimeOsu::acronym(), - Self::NightcoreOsu(_) => NightcoreOsu::acronym(), - Self::HiddenOsu(_) => HiddenOsu::acronym(), - Self::FlashlightOsu(_) => FlashlightOsu::acronym(), - Self::BlindsOsu(_) => BlindsOsu::acronym(), - Self::StrictTrackingOsu(_) => StrictTrackingOsu::acronym(), - Self::AccuracyChallengeOsu(_) => AccuracyChallengeOsu::acronym(), - Self::TargetPracticeOsu(_) => TargetPracticeOsu::acronym(), - Self::DifficultyAdjustOsu(_) => DifficultyAdjustOsu::acronym(), - Self::ClassicOsu(_) => ClassicOsu::acronym(), - Self::RandomOsu(_) => RandomOsu::acronym(), - Self::MirrorOsu(_) => MirrorOsu::acronym(), - Self::AlternateOsu(_) => AlternateOsu::acronym(), - Self::SingleTapOsu(_) => SingleTapOsu::acronym(), - Self::AutoplayOsu(_) => AutoplayOsu::acronym(), - Self::CinemaOsu(_) => CinemaOsu::acronym(), - Self::RelaxOsu(_) => RelaxOsu::acronym(), - Self::AutopilotOsu(_) => AutopilotOsu::acronym(), - Self::SpunOutOsu(_) => SpunOutOsu::acronym(), - Self::TransformOsu(_) => TransformOsu::acronym(), - Self::WiggleOsu(_) => WiggleOsu::acronym(), - Self::SpinInOsu(_) => SpinInOsu::acronym(), - Self::GrowOsu(_) => GrowOsu::acronym(), - Self::DeflateOsu(_) => DeflateOsu::acronym(), - Self::WindUpOsu(_) => WindUpOsu::acronym(), - Self::WindDownOsu(_) => WindDownOsu::acronym(), - Self::TraceableOsu(_) => TraceableOsu::acronym(), - Self::BarrelRollOsu(_) => BarrelRollOsu::acronym(), - Self::ApproachDifferentOsu(_) => ApproachDifferentOsu::acronym(), - Self::MutedOsu(_) => MutedOsu::acronym(), - Self::NoScopeOsu(_) => NoScopeOsu::acronym(), - Self::MagnetisedOsu(_) => MagnetisedOsu::acronym(), - Self::RepelOsu(_) => RepelOsu::acronym(), - Self::AdaptiveSpeedOsu(_) => AdaptiveSpeedOsu::acronym(), - Self::FreezeFrameOsu(_) => FreezeFrameOsu::acronym(), - Self::BubblesOsu(_) => BubblesOsu::acronym(), - Self::SynesthesiaOsu(_) => SynesthesiaOsu::acronym(), - Self::DepthOsu(_) => DepthOsu::acronym(), - Self::TouchDeviceOsu(_) => TouchDeviceOsu::acronym(), - Self::ScoreV2Osu(_) => ScoreV2Osu::acronym(), - Self::EasyTaiko(_) => EasyTaiko::acronym(), - Self::NoFailTaiko(_) => NoFailTaiko::acronym(), - Self::HalfTimeTaiko(_) => HalfTimeTaiko::acronym(), - Self::DaycoreTaiko(_) => DaycoreTaiko::acronym(), - Self::HardRockTaiko(_) => HardRockTaiko::acronym(), - Self::SuddenDeathTaiko(_) => SuddenDeathTaiko::acronym(), - Self::PerfectTaiko(_) => PerfectTaiko::acronym(), - Self::DoubleTimeTaiko(_) => DoubleTimeTaiko::acronym(), - Self::NightcoreTaiko(_) => NightcoreTaiko::acronym(), - Self::HiddenTaiko(_) => HiddenTaiko::acronym(), - Self::FlashlightTaiko(_) => FlashlightTaiko::acronym(), - Self::AccuracyChallengeTaiko(_) => AccuracyChallengeTaiko::acronym(), - Self::RandomTaiko(_) => RandomTaiko::acronym(), - Self::DifficultyAdjustTaiko(_) => DifficultyAdjustTaiko::acronym(), - Self::ClassicTaiko(_) => ClassicTaiko::acronym(), - Self::SwapTaiko(_) => SwapTaiko::acronym(), - Self::SingleTapTaiko(_) => SingleTapTaiko::acronym(), - Self::ConstantSpeedTaiko(_) => ConstantSpeedTaiko::acronym(), - Self::AutoplayTaiko(_) => AutoplayTaiko::acronym(), - Self::CinemaTaiko(_) => CinemaTaiko::acronym(), - Self::RelaxTaiko(_) => RelaxTaiko::acronym(), - Self::WindUpTaiko(_) => WindUpTaiko::acronym(), - Self::WindDownTaiko(_) => WindDownTaiko::acronym(), - Self::MutedTaiko(_) => MutedTaiko::acronym(), - Self::AdaptiveSpeedTaiko(_) => AdaptiveSpeedTaiko::acronym(), - Self::ScoreV2Taiko(_) => ScoreV2Taiko::acronym(), - Self::EasyCatch(_) => EasyCatch::acronym(), - Self::NoFailCatch(_) => NoFailCatch::acronym(), - Self::HalfTimeCatch(_) => HalfTimeCatch::acronym(), - Self::DaycoreCatch(_) => DaycoreCatch::acronym(), - Self::HardRockCatch(_) => HardRockCatch::acronym(), - Self::SuddenDeathCatch(_) => SuddenDeathCatch::acronym(), - Self::PerfectCatch(_) => PerfectCatch::acronym(), - Self::DoubleTimeCatch(_) => DoubleTimeCatch::acronym(), - Self::NightcoreCatch(_) => NightcoreCatch::acronym(), - Self::HiddenCatch(_) => HiddenCatch::acronym(), - Self::FlashlightCatch(_) => FlashlightCatch::acronym(), - Self::AccuracyChallengeCatch(_) => AccuracyChallengeCatch::acronym(), - Self::DifficultyAdjustCatch(_) => DifficultyAdjustCatch::acronym(), - Self::ClassicCatch(_) => ClassicCatch::acronym(), - Self::MirrorCatch(_) => MirrorCatch::acronym(), - Self::AutoplayCatch(_) => AutoplayCatch::acronym(), - Self::CinemaCatch(_) => CinemaCatch::acronym(), - Self::RelaxCatch(_) => RelaxCatch::acronym(), - Self::WindUpCatch(_) => WindUpCatch::acronym(), - Self::WindDownCatch(_) => WindDownCatch::acronym(), - Self::FloatingFruitsCatch(_) => FloatingFruitsCatch::acronym(), - Self::MutedCatch(_) => MutedCatch::acronym(), - Self::NoScopeCatch(_) => NoScopeCatch::acronym(), - Self::ScoreV2Catch(_) => ScoreV2Catch::acronym(), - Self::EasyMania(_) => EasyMania::acronym(), - Self::NoFailMania(_) => NoFailMania::acronym(), - Self::HalfTimeMania(_) => HalfTimeMania::acronym(), - Self::DaycoreMania(_) => DaycoreMania::acronym(), - Self::HardRockMania(_) => HardRockMania::acronym(), - Self::SuddenDeathMania(_) => SuddenDeathMania::acronym(), - Self::PerfectMania(_) => PerfectMania::acronym(), - Self::DoubleTimeMania(_) => DoubleTimeMania::acronym(), - Self::NightcoreMania(_) => NightcoreMania::acronym(), - Self::FadeInMania(_) => FadeInMania::acronym(), - Self::HiddenMania(_) => HiddenMania::acronym(), - Self::CoverMania(_) => CoverMania::acronym(), - Self::FlashlightMania(_) => FlashlightMania::acronym(), - Self::AccuracyChallengeMania(_) => AccuracyChallengeMania::acronym(), - Self::RandomMania(_) => RandomMania::acronym(), - Self::DualStagesMania(_) => DualStagesMania::acronym(), - Self::MirrorMania(_) => MirrorMania::acronym(), - Self::DifficultyAdjustMania(_) => DifficultyAdjustMania::acronym(), - Self::ClassicMania(_) => ClassicMania::acronym(), - Self::InvertMania(_) => InvertMania::acronym(), - Self::ConstantSpeedMania(_) => ConstantSpeedMania::acronym(), - Self::HoldOffMania(_) => HoldOffMania::acronym(), - Self::OneKeyMania(_) => OneKeyMania::acronym(), - Self::TwoKeysMania(_) => TwoKeysMania::acronym(), - Self::ThreeKeysMania(_) => ThreeKeysMania::acronym(), - Self::FourKeysMania(_) => FourKeysMania::acronym(), - Self::FiveKeysMania(_) => FiveKeysMania::acronym(), - Self::SixKeysMania(_) => SixKeysMania::acronym(), - Self::SevenKeysMania(_) => SevenKeysMania::acronym(), - Self::EightKeysMania(_) => EightKeysMania::acronym(), - Self::NineKeysMania(_) => NineKeysMania::acronym(), - Self::TenKeysMania(_) => TenKeysMania::acronym(), - Self::AutoplayMania(_) => AutoplayMania::acronym(), - Self::CinemaMania(_) => CinemaMania::acronym(), - Self::WindUpMania(_) => WindUpMania::acronym(), - Self::WindDownMania(_) => WindDownMania::acronym(), - Self::MutedMania(_) => MutedMania::acronym(), - Self::AdaptiveSpeedMania(_) => AdaptiveSpeedMania::acronym(), - Self::ScoreV2Mania(_) => ScoreV2Mania::acronym(), - Self::UnknownOsu(m) - | Self::UnknownTaiko(m) - | Self::UnknownCatch(m) - | Self::UnknownMania(m) => m.acronym(), - } - } - /// List of [`Acronym`] for mods that are incompatible with this [`GameMod`] - pub fn incompatible_mods(&self) -> Box<[Acronym]> { - match self { - Self::EasyOsu(_) => EasyOsu::incompatible_mods().collect(), - Self::NoFailOsu(_) => NoFailOsu::incompatible_mods().collect(), - Self::HalfTimeOsu(_) => HalfTimeOsu::incompatible_mods().collect(), - Self::DaycoreOsu(_) => DaycoreOsu::incompatible_mods().collect(), - Self::HardRockOsu(_) => HardRockOsu::incompatible_mods().collect(), - Self::SuddenDeathOsu(_) => SuddenDeathOsu::incompatible_mods().collect(), - Self::PerfectOsu(_) => PerfectOsu::incompatible_mods().collect(), - Self::DoubleTimeOsu(_) => DoubleTimeOsu::incompatible_mods().collect(), - Self::NightcoreOsu(_) => NightcoreOsu::incompatible_mods().collect(), - Self::HiddenOsu(_) => HiddenOsu::incompatible_mods().collect(), - Self::FlashlightOsu(_) => FlashlightOsu::incompatible_mods().collect(), - Self::BlindsOsu(_) => BlindsOsu::incompatible_mods().collect(), - Self::StrictTrackingOsu(_) => StrictTrackingOsu::incompatible_mods().collect(), - Self::AccuracyChallengeOsu(_) => AccuracyChallengeOsu::incompatible_mods().collect(), - Self::TargetPracticeOsu(_) => TargetPracticeOsu::incompatible_mods().collect(), - Self::DifficultyAdjustOsu(_) => DifficultyAdjustOsu::incompatible_mods().collect(), - Self::ClassicOsu(_) => ClassicOsu::incompatible_mods().collect(), - Self::RandomOsu(_) => RandomOsu::incompatible_mods().collect(), - Self::MirrorOsu(_) => MirrorOsu::incompatible_mods().collect(), - Self::AlternateOsu(_) => AlternateOsu::incompatible_mods().collect(), - Self::SingleTapOsu(_) => SingleTapOsu::incompatible_mods().collect(), - Self::AutoplayOsu(_) => AutoplayOsu::incompatible_mods().collect(), - Self::CinemaOsu(_) => CinemaOsu::incompatible_mods().collect(), - Self::RelaxOsu(_) => RelaxOsu::incompatible_mods().collect(), - Self::AutopilotOsu(_) => AutopilotOsu::incompatible_mods().collect(), - Self::SpunOutOsu(_) => SpunOutOsu::incompatible_mods().collect(), - Self::TransformOsu(_) => TransformOsu::incompatible_mods().collect(), - Self::WiggleOsu(_) => WiggleOsu::incompatible_mods().collect(), - Self::SpinInOsu(_) => SpinInOsu::incompatible_mods().collect(), - Self::GrowOsu(_) => GrowOsu::incompatible_mods().collect(), - Self::DeflateOsu(_) => DeflateOsu::incompatible_mods().collect(), - Self::WindUpOsu(_) => WindUpOsu::incompatible_mods().collect(), - Self::WindDownOsu(_) => WindDownOsu::incompatible_mods().collect(), - Self::TraceableOsu(_) => TraceableOsu::incompatible_mods().collect(), - Self::BarrelRollOsu(_) => BarrelRollOsu::incompatible_mods().collect(), - Self::ApproachDifferentOsu(_) => ApproachDifferentOsu::incompatible_mods().collect(), - Self::MutedOsu(_) => MutedOsu::incompatible_mods().collect(), - Self::NoScopeOsu(_) => NoScopeOsu::incompatible_mods().collect(), - Self::MagnetisedOsu(_) => MagnetisedOsu::incompatible_mods().collect(), - Self::RepelOsu(_) => RepelOsu::incompatible_mods().collect(), - Self::AdaptiveSpeedOsu(_) => AdaptiveSpeedOsu::incompatible_mods().collect(), - Self::FreezeFrameOsu(_) => FreezeFrameOsu::incompatible_mods().collect(), - Self::BubblesOsu(_) => BubblesOsu::incompatible_mods().collect(), - Self::SynesthesiaOsu(_) => SynesthesiaOsu::incompatible_mods().collect(), - Self::DepthOsu(_) => DepthOsu::incompatible_mods().collect(), - Self::TouchDeviceOsu(_) => TouchDeviceOsu::incompatible_mods().collect(), - Self::ScoreV2Osu(_) => ScoreV2Osu::incompatible_mods().collect(), - Self::EasyTaiko(_) => EasyTaiko::incompatible_mods().collect(), - Self::NoFailTaiko(_) => NoFailTaiko::incompatible_mods().collect(), - Self::HalfTimeTaiko(_) => HalfTimeTaiko::incompatible_mods().collect(), - Self::DaycoreTaiko(_) => DaycoreTaiko::incompatible_mods().collect(), - Self::HardRockTaiko(_) => HardRockTaiko::incompatible_mods().collect(), - Self::SuddenDeathTaiko(_) => SuddenDeathTaiko::incompatible_mods().collect(), - Self::PerfectTaiko(_) => PerfectTaiko::incompatible_mods().collect(), - Self::DoubleTimeTaiko(_) => DoubleTimeTaiko::incompatible_mods().collect(), - Self::NightcoreTaiko(_) => NightcoreTaiko::incompatible_mods().collect(), - Self::HiddenTaiko(_) => HiddenTaiko::incompatible_mods().collect(), - Self::FlashlightTaiko(_) => FlashlightTaiko::incompatible_mods().collect(), - Self::AccuracyChallengeTaiko(_) => { - AccuracyChallengeTaiko::incompatible_mods().collect() - } - Self::RandomTaiko(_) => RandomTaiko::incompatible_mods().collect(), - Self::DifficultyAdjustTaiko(_) => DifficultyAdjustTaiko::incompatible_mods().collect(), - Self::ClassicTaiko(_) => ClassicTaiko::incompatible_mods().collect(), - Self::SwapTaiko(_) => SwapTaiko::incompatible_mods().collect(), - Self::SingleTapTaiko(_) => SingleTapTaiko::incompatible_mods().collect(), - Self::ConstantSpeedTaiko(_) => ConstantSpeedTaiko::incompatible_mods().collect(), - Self::AutoplayTaiko(_) => AutoplayTaiko::incompatible_mods().collect(), - Self::CinemaTaiko(_) => CinemaTaiko::incompatible_mods().collect(), - Self::RelaxTaiko(_) => RelaxTaiko::incompatible_mods().collect(), - Self::WindUpTaiko(_) => WindUpTaiko::incompatible_mods().collect(), - Self::WindDownTaiko(_) => WindDownTaiko::incompatible_mods().collect(), - Self::MutedTaiko(_) => MutedTaiko::incompatible_mods().collect(), - Self::AdaptiveSpeedTaiko(_) => AdaptiveSpeedTaiko::incompatible_mods().collect(), - Self::ScoreV2Taiko(_) => ScoreV2Taiko::incompatible_mods().collect(), - Self::EasyCatch(_) => EasyCatch::incompatible_mods().collect(), - Self::NoFailCatch(_) => NoFailCatch::incompatible_mods().collect(), - Self::HalfTimeCatch(_) => HalfTimeCatch::incompatible_mods().collect(), - Self::DaycoreCatch(_) => DaycoreCatch::incompatible_mods().collect(), - Self::HardRockCatch(_) => HardRockCatch::incompatible_mods().collect(), - Self::SuddenDeathCatch(_) => SuddenDeathCatch::incompatible_mods().collect(), - Self::PerfectCatch(_) => PerfectCatch::incompatible_mods().collect(), - Self::DoubleTimeCatch(_) => DoubleTimeCatch::incompatible_mods().collect(), - Self::NightcoreCatch(_) => NightcoreCatch::incompatible_mods().collect(), - Self::HiddenCatch(_) => HiddenCatch::incompatible_mods().collect(), - Self::FlashlightCatch(_) => FlashlightCatch::incompatible_mods().collect(), - Self::AccuracyChallengeCatch(_) => { - AccuracyChallengeCatch::incompatible_mods().collect() - } - Self::DifficultyAdjustCatch(_) => DifficultyAdjustCatch::incompatible_mods().collect(), - Self::ClassicCatch(_) => ClassicCatch::incompatible_mods().collect(), - Self::MirrorCatch(_) => MirrorCatch::incompatible_mods().collect(), - Self::AutoplayCatch(_) => AutoplayCatch::incompatible_mods().collect(), - Self::CinemaCatch(_) => CinemaCatch::incompatible_mods().collect(), - Self::RelaxCatch(_) => RelaxCatch::incompatible_mods().collect(), - Self::WindUpCatch(_) => WindUpCatch::incompatible_mods().collect(), - Self::WindDownCatch(_) => WindDownCatch::incompatible_mods().collect(), - Self::FloatingFruitsCatch(_) => FloatingFruitsCatch::incompatible_mods().collect(), - Self::MutedCatch(_) => MutedCatch::incompatible_mods().collect(), - Self::NoScopeCatch(_) => NoScopeCatch::incompatible_mods().collect(), - Self::ScoreV2Catch(_) => ScoreV2Catch::incompatible_mods().collect(), - Self::EasyMania(_) => EasyMania::incompatible_mods().collect(), - Self::NoFailMania(_) => NoFailMania::incompatible_mods().collect(), - Self::HalfTimeMania(_) => HalfTimeMania::incompatible_mods().collect(), - Self::DaycoreMania(_) => DaycoreMania::incompatible_mods().collect(), - Self::HardRockMania(_) => HardRockMania::incompatible_mods().collect(), - Self::SuddenDeathMania(_) => SuddenDeathMania::incompatible_mods().collect(), - Self::PerfectMania(_) => PerfectMania::incompatible_mods().collect(), - Self::DoubleTimeMania(_) => DoubleTimeMania::incompatible_mods().collect(), - Self::NightcoreMania(_) => NightcoreMania::incompatible_mods().collect(), - Self::FadeInMania(_) => FadeInMania::incompatible_mods().collect(), - Self::HiddenMania(_) => HiddenMania::incompatible_mods().collect(), - Self::CoverMania(_) => CoverMania::incompatible_mods().collect(), - Self::FlashlightMania(_) => FlashlightMania::incompatible_mods().collect(), - Self::AccuracyChallengeMania(_) => { - AccuracyChallengeMania::incompatible_mods().collect() - } - Self::RandomMania(_) => RandomMania::incompatible_mods().collect(), - Self::DualStagesMania(_) => DualStagesMania::incompatible_mods().collect(), - Self::MirrorMania(_) => MirrorMania::incompatible_mods().collect(), - Self::DifficultyAdjustMania(_) => DifficultyAdjustMania::incompatible_mods().collect(), - Self::ClassicMania(_) => ClassicMania::incompatible_mods().collect(), - Self::InvertMania(_) => InvertMania::incompatible_mods().collect(), - Self::ConstantSpeedMania(_) => ConstantSpeedMania::incompatible_mods().collect(), - Self::HoldOffMania(_) => HoldOffMania::incompatible_mods().collect(), - Self::OneKeyMania(_) => OneKeyMania::incompatible_mods().collect(), - Self::TwoKeysMania(_) => TwoKeysMania::incompatible_mods().collect(), - Self::ThreeKeysMania(_) => ThreeKeysMania::incompatible_mods().collect(), - Self::FourKeysMania(_) => FourKeysMania::incompatible_mods().collect(), - Self::FiveKeysMania(_) => FiveKeysMania::incompatible_mods().collect(), - Self::SixKeysMania(_) => SixKeysMania::incompatible_mods().collect(), - Self::SevenKeysMania(_) => SevenKeysMania::incompatible_mods().collect(), - Self::EightKeysMania(_) => EightKeysMania::incompatible_mods().collect(), - Self::NineKeysMania(_) => NineKeysMania::incompatible_mods().collect(), - Self::TenKeysMania(_) => TenKeysMania::incompatible_mods().collect(), - Self::AutoplayMania(_) => AutoplayMania::incompatible_mods().collect(), - Self::CinemaMania(_) => CinemaMania::incompatible_mods().collect(), - Self::WindUpMania(_) => WindUpMania::incompatible_mods().collect(), - Self::WindDownMania(_) => WindDownMania::incompatible_mods().collect(), - Self::MutedMania(_) => MutedMania::incompatible_mods().collect(), - Self::AdaptiveSpeedMania(_) => AdaptiveSpeedMania::incompatible_mods().collect(), - Self::ScoreV2Mania(_) => ScoreV2Mania::incompatible_mods().collect(), - _ => UnknownMod::incompatible_mods().collect(), - } - } - /// The description of this [`GameMod`] - pub const fn description(&self) -> &'static str { - match self { - Self::EasyOsu(_) => EasyOsu::description(), - Self::NoFailOsu(_) => NoFailOsu::description(), - Self::HalfTimeOsu(_) => HalfTimeOsu::description(), - Self::DaycoreOsu(_) => DaycoreOsu::description(), - Self::HardRockOsu(_) => HardRockOsu::description(), - Self::SuddenDeathOsu(_) => SuddenDeathOsu::description(), - Self::PerfectOsu(_) => PerfectOsu::description(), - Self::DoubleTimeOsu(_) => DoubleTimeOsu::description(), - Self::NightcoreOsu(_) => NightcoreOsu::description(), - Self::HiddenOsu(_) => HiddenOsu::description(), - Self::FlashlightOsu(_) => FlashlightOsu::description(), - Self::BlindsOsu(_) => BlindsOsu::description(), - Self::StrictTrackingOsu(_) => StrictTrackingOsu::description(), - Self::AccuracyChallengeOsu(_) => AccuracyChallengeOsu::description(), - Self::TargetPracticeOsu(_) => TargetPracticeOsu::description(), - Self::DifficultyAdjustOsu(_) => DifficultyAdjustOsu::description(), - Self::ClassicOsu(_) => ClassicOsu::description(), - Self::RandomOsu(_) => RandomOsu::description(), - Self::MirrorOsu(_) => MirrorOsu::description(), - Self::AlternateOsu(_) => AlternateOsu::description(), - Self::SingleTapOsu(_) => SingleTapOsu::description(), - Self::AutoplayOsu(_) => AutoplayOsu::description(), - Self::CinemaOsu(_) => CinemaOsu::description(), - Self::RelaxOsu(_) => RelaxOsu::description(), - Self::AutopilotOsu(_) => AutopilotOsu::description(), - Self::SpunOutOsu(_) => SpunOutOsu::description(), - Self::TransformOsu(_) => TransformOsu::description(), - Self::WiggleOsu(_) => WiggleOsu::description(), - Self::SpinInOsu(_) => SpinInOsu::description(), - Self::GrowOsu(_) => GrowOsu::description(), - Self::DeflateOsu(_) => DeflateOsu::description(), - Self::WindUpOsu(_) => WindUpOsu::description(), - Self::WindDownOsu(_) => WindDownOsu::description(), - Self::TraceableOsu(_) => TraceableOsu::description(), - Self::BarrelRollOsu(_) => BarrelRollOsu::description(), - Self::ApproachDifferentOsu(_) => ApproachDifferentOsu::description(), - Self::MutedOsu(_) => MutedOsu::description(), - Self::NoScopeOsu(_) => NoScopeOsu::description(), - Self::MagnetisedOsu(_) => MagnetisedOsu::description(), - Self::RepelOsu(_) => RepelOsu::description(), - Self::AdaptiveSpeedOsu(_) => AdaptiveSpeedOsu::description(), - Self::FreezeFrameOsu(_) => FreezeFrameOsu::description(), - Self::BubblesOsu(_) => BubblesOsu::description(), - Self::SynesthesiaOsu(_) => SynesthesiaOsu::description(), - Self::DepthOsu(_) => DepthOsu::description(), - Self::TouchDeviceOsu(_) => TouchDeviceOsu::description(), - Self::ScoreV2Osu(_) => ScoreV2Osu::description(), - Self::EasyTaiko(_) => EasyTaiko::description(), - Self::NoFailTaiko(_) => NoFailTaiko::description(), - Self::HalfTimeTaiko(_) => HalfTimeTaiko::description(), - Self::DaycoreTaiko(_) => DaycoreTaiko::description(), - Self::HardRockTaiko(_) => HardRockTaiko::description(), - Self::SuddenDeathTaiko(_) => SuddenDeathTaiko::description(), - Self::PerfectTaiko(_) => PerfectTaiko::description(), - Self::DoubleTimeTaiko(_) => DoubleTimeTaiko::description(), - Self::NightcoreTaiko(_) => NightcoreTaiko::description(), - Self::HiddenTaiko(_) => HiddenTaiko::description(), - Self::FlashlightTaiko(_) => FlashlightTaiko::description(), - Self::AccuracyChallengeTaiko(_) => AccuracyChallengeTaiko::description(), - Self::RandomTaiko(_) => RandomTaiko::description(), - Self::DifficultyAdjustTaiko(_) => DifficultyAdjustTaiko::description(), - Self::ClassicTaiko(_) => ClassicTaiko::description(), - Self::SwapTaiko(_) => SwapTaiko::description(), - Self::SingleTapTaiko(_) => SingleTapTaiko::description(), - Self::ConstantSpeedTaiko(_) => ConstantSpeedTaiko::description(), - Self::AutoplayTaiko(_) => AutoplayTaiko::description(), - Self::CinemaTaiko(_) => CinemaTaiko::description(), - Self::RelaxTaiko(_) => RelaxTaiko::description(), - Self::WindUpTaiko(_) => WindUpTaiko::description(), - Self::WindDownTaiko(_) => WindDownTaiko::description(), - Self::MutedTaiko(_) => MutedTaiko::description(), - Self::AdaptiveSpeedTaiko(_) => AdaptiveSpeedTaiko::description(), - Self::ScoreV2Taiko(_) => ScoreV2Taiko::description(), - Self::EasyCatch(_) => EasyCatch::description(), - Self::NoFailCatch(_) => NoFailCatch::description(), - Self::HalfTimeCatch(_) => HalfTimeCatch::description(), - Self::DaycoreCatch(_) => DaycoreCatch::description(), - Self::HardRockCatch(_) => HardRockCatch::description(), - Self::SuddenDeathCatch(_) => SuddenDeathCatch::description(), - Self::PerfectCatch(_) => PerfectCatch::description(), - Self::DoubleTimeCatch(_) => DoubleTimeCatch::description(), - Self::NightcoreCatch(_) => NightcoreCatch::description(), - Self::HiddenCatch(_) => HiddenCatch::description(), - Self::FlashlightCatch(_) => FlashlightCatch::description(), - Self::AccuracyChallengeCatch(_) => AccuracyChallengeCatch::description(), - Self::DifficultyAdjustCatch(_) => DifficultyAdjustCatch::description(), - Self::ClassicCatch(_) => ClassicCatch::description(), - Self::MirrorCatch(_) => MirrorCatch::description(), - Self::AutoplayCatch(_) => AutoplayCatch::description(), - Self::CinemaCatch(_) => CinemaCatch::description(), - Self::RelaxCatch(_) => RelaxCatch::description(), - Self::WindUpCatch(_) => WindUpCatch::description(), - Self::WindDownCatch(_) => WindDownCatch::description(), - Self::FloatingFruitsCatch(_) => FloatingFruitsCatch::description(), - Self::MutedCatch(_) => MutedCatch::description(), - Self::NoScopeCatch(_) => NoScopeCatch::description(), - Self::ScoreV2Catch(_) => ScoreV2Catch::description(), - Self::EasyMania(_) => EasyMania::description(), - Self::NoFailMania(_) => NoFailMania::description(), - Self::HalfTimeMania(_) => HalfTimeMania::description(), - Self::DaycoreMania(_) => DaycoreMania::description(), - Self::HardRockMania(_) => HardRockMania::description(), - Self::SuddenDeathMania(_) => SuddenDeathMania::description(), - Self::PerfectMania(_) => PerfectMania::description(), - Self::DoubleTimeMania(_) => DoubleTimeMania::description(), - Self::NightcoreMania(_) => NightcoreMania::description(), - Self::FadeInMania(_) => FadeInMania::description(), - Self::HiddenMania(_) => HiddenMania::description(), - Self::CoverMania(_) => CoverMania::description(), - Self::FlashlightMania(_) => FlashlightMania::description(), - Self::AccuracyChallengeMania(_) => AccuracyChallengeMania::description(), - Self::RandomMania(_) => RandomMania::description(), - Self::DualStagesMania(_) => DualStagesMania::description(), - Self::MirrorMania(_) => MirrorMania::description(), - Self::DifficultyAdjustMania(_) => DifficultyAdjustMania::description(), - Self::ClassicMania(_) => ClassicMania::description(), - Self::InvertMania(_) => InvertMania::description(), - Self::ConstantSpeedMania(_) => ConstantSpeedMania::description(), - Self::HoldOffMania(_) => HoldOffMania::description(), - Self::OneKeyMania(_) => OneKeyMania::description(), - Self::TwoKeysMania(_) => TwoKeysMania::description(), - Self::ThreeKeysMania(_) => ThreeKeysMania::description(), - Self::FourKeysMania(_) => FourKeysMania::description(), - Self::FiveKeysMania(_) => FiveKeysMania::description(), - Self::SixKeysMania(_) => SixKeysMania::description(), - Self::SevenKeysMania(_) => SevenKeysMania::description(), - Self::EightKeysMania(_) => EightKeysMania::description(), - Self::NineKeysMania(_) => NineKeysMania::description(), - Self::TenKeysMania(_) => TenKeysMania::description(), - Self::AutoplayMania(_) => AutoplayMania::description(), - Self::CinemaMania(_) => CinemaMania::description(), - Self::WindUpMania(_) => WindUpMania::description(), - Self::WindDownMania(_) => WindDownMania::description(), - Self::MutedMania(_) => MutedMania::description(), - Self::AdaptiveSpeedMania(_) => AdaptiveSpeedMania::description(), - Self::ScoreV2Mania(_) => ScoreV2Mania::description(), - _ => UnknownMod::description(), - } - } - /// The [`GameModKind`] of this [`GameMod`] - pub const fn kind(&self) -> GameModKind { - match self { - Self::EasyOsu(_) => EasyOsu::kind(), - Self::NoFailOsu(_) => NoFailOsu::kind(), - Self::HalfTimeOsu(_) => HalfTimeOsu::kind(), - Self::DaycoreOsu(_) => DaycoreOsu::kind(), - Self::HardRockOsu(_) => HardRockOsu::kind(), - Self::SuddenDeathOsu(_) => SuddenDeathOsu::kind(), - Self::PerfectOsu(_) => PerfectOsu::kind(), - Self::DoubleTimeOsu(_) => DoubleTimeOsu::kind(), - Self::NightcoreOsu(_) => NightcoreOsu::kind(), - Self::HiddenOsu(_) => HiddenOsu::kind(), - Self::FlashlightOsu(_) => FlashlightOsu::kind(), - Self::BlindsOsu(_) => BlindsOsu::kind(), - Self::StrictTrackingOsu(_) => StrictTrackingOsu::kind(), - Self::AccuracyChallengeOsu(_) => AccuracyChallengeOsu::kind(), - Self::TargetPracticeOsu(_) => TargetPracticeOsu::kind(), - Self::DifficultyAdjustOsu(_) => DifficultyAdjustOsu::kind(), - Self::ClassicOsu(_) => ClassicOsu::kind(), - Self::RandomOsu(_) => RandomOsu::kind(), - Self::MirrorOsu(_) => MirrorOsu::kind(), - Self::AlternateOsu(_) => AlternateOsu::kind(), - Self::SingleTapOsu(_) => SingleTapOsu::kind(), - Self::AutoplayOsu(_) => AutoplayOsu::kind(), - Self::CinemaOsu(_) => CinemaOsu::kind(), - Self::RelaxOsu(_) => RelaxOsu::kind(), - Self::AutopilotOsu(_) => AutopilotOsu::kind(), - Self::SpunOutOsu(_) => SpunOutOsu::kind(), - Self::TransformOsu(_) => TransformOsu::kind(), - Self::WiggleOsu(_) => WiggleOsu::kind(), - Self::SpinInOsu(_) => SpinInOsu::kind(), - Self::GrowOsu(_) => GrowOsu::kind(), - Self::DeflateOsu(_) => DeflateOsu::kind(), - Self::WindUpOsu(_) => WindUpOsu::kind(), - Self::WindDownOsu(_) => WindDownOsu::kind(), - Self::TraceableOsu(_) => TraceableOsu::kind(), - Self::BarrelRollOsu(_) => BarrelRollOsu::kind(), - Self::ApproachDifferentOsu(_) => ApproachDifferentOsu::kind(), - Self::MutedOsu(_) => MutedOsu::kind(), - Self::NoScopeOsu(_) => NoScopeOsu::kind(), - Self::MagnetisedOsu(_) => MagnetisedOsu::kind(), - Self::RepelOsu(_) => RepelOsu::kind(), - Self::AdaptiveSpeedOsu(_) => AdaptiveSpeedOsu::kind(), - Self::FreezeFrameOsu(_) => FreezeFrameOsu::kind(), - Self::BubblesOsu(_) => BubblesOsu::kind(), - Self::SynesthesiaOsu(_) => SynesthesiaOsu::kind(), - Self::DepthOsu(_) => DepthOsu::kind(), - Self::TouchDeviceOsu(_) => TouchDeviceOsu::kind(), - Self::ScoreV2Osu(_) => ScoreV2Osu::kind(), - Self::EasyTaiko(_) => EasyTaiko::kind(), - Self::NoFailTaiko(_) => NoFailTaiko::kind(), - Self::HalfTimeTaiko(_) => HalfTimeTaiko::kind(), - Self::DaycoreTaiko(_) => DaycoreTaiko::kind(), - Self::HardRockTaiko(_) => HardRockTaiko::kind(), - Self::SuddenDeathTaiko(_) => SuddenDeathTaiko::kind(), - Self::PerfectTaiko(_) => PerfectTaiko::kind(), - Self::DoubleTimeTaiko(_) => DoubleTimeTaiko::kind(), - Self::NightcoreTaiko(_) => NightcoreTaiko::kind(), - Self::HiddenTaiko(_) => HiddenTaiko::kind(), - Self::FlashlightTaiko(_) => FlashlightTaiko::kind(), - Self::AccuracyChallengeTaiko(_) => AccuracyChallengeTaiko::kind(), - Self::RandomTaiko(_) => RandomTaiko::kind(), - Self::DifficultyAdjustTaiko(_) => DifficultyAdjustTaiko::kind(), - Self::ClassicTaiko(_) => ClassicTaiko::kind(), - Self::SwapTaiko(_) => SwapTaiko::kind(), - Self::SingleTapTaiko(_) => SingleTapTaiko::kind(), - Self::ConstantSpeedTaiko(_) => ConstantSpeedTaiko::kind(), - Self::AutoplayTaiko(_) => AutoplayTaiko::kind(), - Self::CinemaTaiko(_) => CinemaTaiko::kind(), - Self::RelaxTaiko(_) => RelaxTaiko::kind(), - Self::WindUpTaiko(_) => WindUpTaiko::kind(), - Self::WindDownTaiko(_) => WindDownTaiko::kind(), - Self::MutedTaiko(_) => MutedTaiko::kind(), - Self::AdaptiveSpeedTaiko(_) => AdaptiveSpeedTaiko::kind(), - Self::ScoreV2Taiko(_) => ScoreV2Taiko::kind(), - Self::EasyCatch(_) => EasyCatch::kind(), - Self::NoFailCatch(_) => NoFailCatch::kind(), - Self::HalfTimeCatch(_) => HalfTimeCatch::kind(), - Self::DaycoreCatch(_) => DaycoreCatch::kind(), - Self::HardRockCatch(_) => HardRockCatch::kind(), - Self::SuddenDeathCatch(_) => SuddenDeathCatch::kind(), - Self::PerfectCatch(_) => PerfectCatch::kind(), - Self::DoubleTimeCatch(_) => DoubleTimeCatch::kind(), - Self::NightcoreCatch(_) => NightcoreCatch::kind(), - Self::HiddenCatch(_) => HiddenCatch::kind(), - Self::FlashlightCatch(_) => FlashlightCatch::kind(), - Self::AccuracyChallengeCatch(_) => AccuracyChallengeCatch::kind(), - Self::DifficultyAdjustCatch(_) => DifficultyAdjustCatch::kind(), - Self::ClassicCatch(_) => ClassicCatch::kind(), - Self::MirrorCatch(_) => MirrorCatch::kind(), - Self::AutoplayCatch(_) => AutoplayCatch::kind(), - Self::CinemaCatch(_) => CinemaCatch::kind(), - Self::RelaxCatch(_) => RelaxCatch::kind(), - Self::WindUpCatch(_) => WindUpCatch::kind(), - Self::WindDownCatch(_) => WindDownCatch::kind(), - Self::FloatingFruitsCatch(_) => FloatingFruitsCatch::kind(), - Self::MutedCatch(_) => MutedCatch::kind(), - Self::NoScopeCatch(_) => NoScopeCatch::kind(), - Self::ScoreV2Catch(_) => ScoreV2Catch::kind(), - Self::EasyMania(_) => EasyMania::kind(), - Self::NoFailMania(_) => NoFailMania::kind(), - Self::HalfTimeMania(_) => HalfTimeMania::kind(), - Self::DaycoreMania(_) => DaycoreMania::kind(), - Self::HardRockMania(_) => HardRockMania::kind(), - Self::SuddenDeathMania(_) => SuddenDeathMania::kind(), - Self::PerfectMania(_) => PerfectMania::kind(), - Self::DoubleTimeMania(_) => DoubleTimeMania::kind(), - Self::NightcoreMania(_) => NightcoreMania::kind(), - Self::FadeInMania(_) => FadeInMania::kind(), - Self::HiddenMania(_) => HiddenMania::kind(), - Self::CoverMania(_) => CoverMania::kind(), - Self::FlashlightMania(_) => FlashlightMania::kind(), - Self::AccuracyChallengeMania(_) => AccuracyChallengeMania::kind(), - Self::RandomMania(_) => RandomMania::kind(), - Self::DualStagesMania(_) => DualStagesMania::kind(), - Self::MirrorMania(_) => MirrorMania::kind(), - Self::DifficultyAdjustMania(_) => DifficultyAdjustMania::kind(), - Self::ClassicMania(_) => ClassicMania::kind(), - Self::InvertMania(_) => InvertMania::kind(), - Self::ConstantSpeedMania(_) => ConstantSpeedMania::kind(), - Self::HoldOffMania(_) => HoldOffMania::kind(), - Self::OneKeyMania(_) => OneKeyMania::kind(), - Self::TwoKeysMania(_) => TwoKeysMania::kind(), - Self::ThreeKeysMania(_) => ThreeKeysMania::kind(), - Self::FourKeysMania(_) => FourKeysMania::kind(), - Self::FiveKeysMania(_) => FiveKeysMania::kind(), - Self::SixKeysMania(_) => SixKeysMania::kind(), - Self::SevenKeysMania(_) => SevenKeysMania::kind(), - Self::EightKeysMania(_) => EightKeysMania::kind(), - Self::NineKeysMania(_) => NineKeysMania::kind(), - Self::TenKeysMania(_) => TenKeysMania::kind(), - Self::AutoplayMania(_) => AutoplayMania::kind(), - Self::CinemaMania(_) => CinemaMania::kind(), - Self::WindUpMania(_) => WindUpMania::kind(), - Self::WindDownMania(_) => WindDownMania::kind(), - Self::MutedMania(_) => MutedMania::kind(), - Self::AdaptiveSpeedMania(_) => AdaptiveSpeedMania::kind(), - Self::ScoreV2Mania(_) => ScoreV2Mania::kind(), - _ => UnknownMod::kind(), - } - } - /// Optional bit value of this [`GameMod`] - /// - /// See - pub const fn bits(&self) -> Option { - match self { - Self::EasyOsu(_) => Some(EasyOsu::bits()), - Self::NoFailOsu(_) => Some(NoFailOsu::bits()), - Self::HalfTimeOsu(_) => Some(HalfTimeOsu::bits()), - Self::HardRockOsu(_) => Some(HardRockOsu::bits()), - Self::SuddenDeathOsu(_) => Some(SuddenDeathOsu::bits()), - Self::PerfectOsu(_) => Some(PerfectOsu::bits()), - Self::DoubleTimeOsu(_) => Some(DoubleTimeOsu::bits()), - Self::NightcoreOsu(_) => Some(NightcoreOsu::bits()), - Self::HiddenOsu(_) => Some(HiddenOsu::bits()), - Self::FlashlightOsu(_) => Some(FlashlightOsu::bits()), - Self::TargetPracticeOsu(_) => Some(TargetPracticeOsu::bits()), - Self::RandomOsu(_) => Some(RandomOsu::bits()), - Self::MirrorOsu(_) => Some(MirrorOsu::bits()), - Self::AutoplayOsu(_) => Some(AutoplayOsu::bits()), - Self::CinemaOsu(_) => Some(CinemaOsu::bits()), - Self::RelaxOsu(_) => Some(RelaxOsu::bits()), - Self::AutopilotOsu(_) => Some(AutopilotOsu::bits()), - Self::SpunOutOsu(_) => Some(SpunOutOsu::bits()), - Self::TouchDeviceOsu(_) => Some(TouchDeviceOsu::bits()), - Self::ScoreV2Osu(_) => Some(ScoreV2Osu::bits()), - Self::EasyTaiko(_) => Some(EasyTaiko::bits()), - Self::NoFailTaiko(_) => Some(NoFailTaiko::bits()), - Self::HalfTimeTaiko(_) => Some(HalfTimeTaiko::bits()), - Self::HardRockTaiko(_) => Some(HardRockTaiko::bits()), - Self::SuddenDeathTaiko(_) => Some(SuddenDeathTaiko::bits()), - Self::PerfectTaiko(_) => Some(PerfectTaiko::bits()), - Self::DoubleTimeTaiko(_) => Some(DoubleTimeTaiko::bits()), - Self::NightcoreTaiko(_) => Some(NightcoreTaiko::bits()), - Self::HiddenTaiko(_) => Some(HiddenTaiko::bits()), - Self::FlashlightTaiko(_) => Some(FlashlightTaiko::bits()), - Self::RandomTaiko(_) => Some(RandomTaiko::bits()), - Self::AutoplayTaiko(_) => Some(AutoplayTaiko::bits()), - Self::CinemaTaiko(_) => Some(CinemaTaiko::bits()), - Self::RelaxTaiko(_) => Some(RelaxTaiko::bits()), - Self::ScoreV2Taiko(_) => Some(ScoreV2Taiko::bits()), - Self::EasyCatch(_) => Some(EasyCatch::bits()), - Self::NoFailCatch(_) => Some(NoFailCatch::bits()), - Self::HalfTimeCatch(_) => Some(HalfTimeCatch::bits()), - Self::HardRockCatch(_) => Some(HardRockCatch::bits()), - Self::SuddenDeathCatch(_) => Some(SuddenDeathCatch::bits()), - Self::PerfectCatch(_) => Some(PerfectCatch::bits()), - Self::DoubleTimeCatch(_) => Some(DoubleTimeCatch::bits()), - Self::NightcoreCatch(_) => Some(NightcoreCatch::bits()), - Self::HiddenCatch(_) => Some(HiddenCatch::bits()), - Self::FlashlightCatch(_) => Some(FlashlightCatch::bits()), - Self::MirrorCatch(_) => Some(MirrorCatch::bits()), - Self::AutoplayCatch(_) => Some(AutoplayCatch::bits()), - Self::CinemaCatch(_) => Some(CinemaCatch::bits()), - Self::RelaxCatch(_) => Some(RelaxCatch::bits()), - Self::ScoreV2Catch(_) => Some(ScoreV2Catch::bits()), - Self::EasyMania(_) => Some(EasyMania::bits()), - Self::NoFailMania(_) => Some(NoFailMania::bits()), - Self::HalfTimeMania(_) => Some(HalfTimeMania::bits()), - Self::HardRockMania(_) => Some(HardRockMania::bits()), - Self::SuddenDeathMania(_) => Some(SuddenDeathMania::bits()), - Self::PerfectMania(_) => Some(PerfectMania::bits()), - Self::DoubleTimeMania(_) => Some(DoubleTimeMania::bits()), - Self::NightcoreMania(_) => Some(NightcoreMania::bits()), - Self::FadeInMania(_) => Some(FadeInMania::bits()), - Self::HiddenMania(_) => Some(HiddenMania::bits()), - Self::FlashlightMania(_) => Some(FlashlightMania::bits()), - Self::RandomMania(_) => Some(RandomMania::bits()), - Self::DualStagesMania(_) => Some(DualStagesMania::bits()), - Self::MirrorMania(_) => Some(MirrorMania::bits()), - Self::OneKeyMania(_) => Some(OneKeyMania::bits()), - Self::TwoKeysMania(_) => Some(TwoKeysMania::bits()), - Self::ThreeKeysMania(_) => Some(ThreeKeysMania::bits()), - Self::FourKeysMania(_) => Some(FourKeysMania::bits()), - Self::FiveKeysMania(_) => Some(FiveKeysMania::bits()), - Self::SixKeysMania(_) => Some(SixKeysMania::bits()), - Self::SevenKeysMania(_) => Some(SevenKeysMania::bits()), - Self::EightKeysMania(_) => Some(EightKeysMania::bits()), - Self::NineKeysMania(_) => Some(NineKeysMania::bits()), - Self::AutoplayMania(_) => Some(AutoplayMania::bits()), - Self::CinemaMania(_) => Some(CinemaMania::bits()), - Self::ScoreV2Mania(_) => Some(ScoreV2Mania::bits()), - _ => None, - } - } - /// The [`GameMode`] of a [`GameMod`] - pub const fn mode(&self) -> GameMode { - match self { - Self::EasyOsu(_) - | Self::NoFailOsu(_) - | Self::HalfTimeOsu(_) - | Self::DaycoreOsu(_) - | Self::HardRockOsu(_) - | Self::SuddenDeathOsu(_) - | Self::PerfectOsu(_) - | Self::DoubleTimeOsu(_) - | Self::NightcoreOsu(_) - | Self::HiddenOsu(_) - | Self::FlashlightOsu(_) - | Self::BlindsOsu(_) - | Self::StrictTrackingOsu(_) - | Self::AccuracyChallengeOsu(_) - | Self::TargetPracticeOsu(_) - | Self::DifficultyAdjustOsu(_) - | Self::ClassicOsu(_) - | Self::RandomOsu(_) - | Self::MirrorOsu(_) - | Self::AlternateOsu(_) - | Self::SingleTapOsu(_) - | Self::AutoplayOsu(_) - | Self::CinemaOsu(_) - | Self::RelaxOsu(_) - | Self::AutopilotOsu(_) - | Self::SpunOutOsu(_) - | Self::TransformOsu(_) - | Self::WiggleOsu(_) - | Self::SpinInOsu(_) - | Self::GrowOsu(_) - | Self::DeflateOsu(_) - | Self::WindUpOsu(_) - | Self::WindDownOsu(_) - | Self::TraceableOsu(_) - | Self::BarrelRollOsu(_) - | Self::ApproachDifferentOsu(_) - | Self::MutedOsu(_) - | Self::NoScopeOsu(_) - | Self::MagnetisedOsu(_) - | Self::RepelOsu(_) - | Self::AdaptiveSpeedOsu(_) - | Self::FreezeFrameOsu(_) - | Self::BubblesOsu(_) - | Self::SynesthesiaOsu(_) - | Self::DepthOsu(_) - | Self::TouchDeviceOsu(_) - | Self::ScoreV2Osu(_) - | Self::UnknownOsu(_) => GameMode::Osu, - Self::EasyTaiko(_) - | Self::NoFailTaiko(_) - | Self::HalfTimeTaiko(_) - | Self::DaycoreTaiko(_) - | Self::HardRockTaiko(_) - | Self::SuddenDeathTaiko(_) - | Self::PerfectTaiko(_) - | Self::DoubleTimeTaiko(_) - | Self::NightcoreTaiko(_) - | Self::HiddenTaiko(_) - | Self::FlashlightTaiko(_) - | Self::AccuracyChallengeTaiko(_) - | Self::RandomTaiko(_) - | Self::DifficultyAdjustTaiko(_) - | Self::ClassicTaiko(_) - | Self::SwapTaiko(_) - | Self::SingleTapTaiko(_) - | Self::ConstantSpeedTaiko(_) - | Self::AutoplayTaiko(_) - | Self::CinemaTaiko(_) - | Self::RelaxTaiko(_) - | Self::WindUpTaiko(_) - | Self::WindDownTaiko(_) - | Self::MutedTaiko(_) - | Self::AdaptiveSpeedTaiko(_) - | Self::ScoreV2Taiko(_) - | Self::UnknownTaiko(_) => GameMode::Taiko, - Self::EasyCatch(_) - | Self::NoFailCatch(_) - | Self::HalfTimeCatch(_) - | Self::DaycoreCatch(_) - | Self::HardRockCatch(_) - | Self::SuddenDeathCatch(_) - | Self::PerfectCatch(_) - | Self::DoubleTimeCatch(_) - | Self::NightcoreCatch(_) - | Self::HiddenCatch(_) - | Self::FlashlightCatch(_) - | Self::AccuracyChallengeCatch(_) - | Self::DifficultyAdjustCatch(_) - | Self::ClassicCatch(_) - | Self::MirrorCatch(_) - | Self::AutoplayCatch(_) - | Self::CinemaCatch(_) - | Self::RelaxCatch(_) - | Self::WindUpCatch(_) - | Self::WindDownCatch(_) - | Self::FloatingFruitsCatch(_) - | Self::MutedCatch(_) - | Self::NoScopeCatch(_) - | Self::ScoreV2Catch(_) - | Self::UnknownCatch(_) => GameMode::Catch, - Self::EasyMania(_) - | Self::NoFailMania(_) - | Self::HalfTimeMania(_) - | Self::DaycoreMania(_) - | Self::HardRockMania(_) - | Self::SuddenDeathMania(_) - | Self::PerfectMania(_) - | Self::DoubleTimeMania(_) - | Self::NightcoreMania(_) - | Self::FadeInMania(_) - | Self::HiddenMania(_) - | Self::CoverMania(_) - | Self::FlashlightMania(_) - | Self::AccuracyChallengeMania(_) - | Self::RandomMania(_) - | Self::DualStagesMania(_) - | Self::MirrorMania(_) - | Self::DifficultyAdjustMania(_) - | Self::ClassicMania(_) - | Self::InvertMania(_) - | Self::ConstantSpeedMania(_) - | Self::HoldOffMania(_) - | Self::OneKeyMania(_) - | Self::TwoKeysMania(_) - | Self::ThreeKeysMania(_) - | Self::FourKeysMania(_) - | Self::FiveKeysMania(_) - | Self::SixKeysMania(_) - | Self::SevenKeysMania(_) - | Self::EightKeysMania(_) - | Self::NineKeysMania(_) - | Self::TenKeysMania(_) - | Self::AutoplayMania(_) - | Self::CinemaMania(_) - | Self::WindUpMania(_) - | Self::WindDownMania(_) - | Self::MutedMania(_) - | Self::AdaptiveSpeedMania(_) - | Self::ScoreV2Mania(_) - | Self::UnknownMania(_) => GameMode::Mania, - } - } - /// The kind of a [`GameMod`] when ignoring the mode - pub const fn intermode(&self) -> GameModIntermode { - match self { - Self::EasyOsu(_) => GameModIntermode::Easy, - Self::NoFailOsu(_) => GameModIntermode::NoFail, - Self::HalfTimeOsu(_) => GameModIntermode::HalfTime, - Self::DaycoreOsu(_) => GameModIntermode::Daycore, - Self::HardRockOsu(_) => GameModIntermode::HardRock, - Self::SuddenDeathOsu(_) => GameModIntermode::SuddenDeath, - Self::PerfectOsu(_) => GameModIntermode::Perfect, - Self::DoubleTimeOsu(_) => GameModIntermode::DoubleTime, - Self::NightcoreOsu(_) => GameModIntermode::Nightcore, - Self::HiddenOsu(_) => GameModIntermode::Hidden, - Self::FlashlightOsu(_) => GameModIntermode::Flashlight, - Self::BlindsOsu(_) => GameModIntermode::Blinds, - Self::StrictTrackingOsu(_) => GameModIntermode::StrictTracking, - Self::AccuracyChallengeOsu(_) => GameModIntermode::AccuracyChallenge, - Self::TargetPracticeOsu(_) => GameModIntermode::TargetPractice, - Self::DifficultyAdjustOsu(_) => GameModIntermode::DifficultyAdjust, - Self::ClassicOsu(_) => GameModIntermode::Classic, - Self::RandomOsu(_) => GameModIntermode::Random, - Self::MirrorOsu(_) => GameModIntermode::Mirror, - Self::AlternateOsu(_) => GameModIntermode::Alternate, - Self::SingleTapOsu(_) => GameModIntermode::SingleTap, - Self::AutoplayOsu(_) => GameModIntermode::Autoplay, - Self::CinemaOsu(_) => GameModIntermode::Cinema, - Self::RelaxOsu(_) => GameModIntermode::Relax, - Self::AutopilotOsu(_) => GameModIntermode::Autopilot, - Self::SpunOutOsu(_) => GameModIntermode::SpunOut, - Self::TransformOsu(_) => GameModIntermode::Transform, - Self::WiggleOsu(_) => GameModIntermode::Wiggle, - Self::SpinInOsu(_) => GameModIntermode::SpinIn, - Self::GrowOsu(_) => GameModIntermode::Grow, - Self::DeflateOsu(_) => GameModIntermode::Deflate, - Self::WindUpOsu(_) => GameModIntermode::WindUp, - Self::WindDownOsu(_) => GameModIntermode::WindDown, - Self::TraceableOsu(_) => GameModIntermode::Traceable, - Self::BarrelRollOsu(_) => GameModIntermode::BarrelRoll, - Self::ApproachDifferentOsu(_) => GameModIntermode::ApproachDifferent, - Self::MutedOsu(_) => GameModIntermode::Muted, - Self::NoScopeOsu(_) => GameModIntermode::NoScope, - Self::MagnetisedOsu(_) => GameModIntermode::Magnetised, - Self::RepelOsu(_) => GameModIntermode::Repel, - Self::AdaptiveSpeedOsu(_) => GameModIntermode::AdaptiveSpeed, - Self::FreezeFrameOsu(_) => GameModIntermode::FreezeFrame, - Self::BubblesOsu(_) => GameModIntermode::Bubbles, - Self::SynesthesiaOsu(_) => GameModIntermode::Synesthesia, - Self::DepthOsu(_) => GameModIntermode::Depth, - Self::TouchDeviceOsu(_) => GameModIntermode::TouchDevice, - Self::ScoreV2Osu(_) => GameModIntermode::ScoreV2, - Self::EasyTaiko(_) => GameModIntermode::Easy, - Self::NoFailTaiko(_) => GameModIntermode::NoFail, - Self::HalfTimeTaiko(_) => GameModIntermode::HalfTime, - Self::DaycoreTaiko(_) => GameModIntermode::Daycore, - Self::HardRockTaiko(_) => GameModIntermode::HardRock, - Self::SuddenDeathTaiko(_) => GameModIntermode::SuddenDeath, - Self::PerfectTaiko(_) => GameModIntermode::Perfect, - Self::DoubleTimeTaiko(_) => GameModIntermode::DoubleTime, - Self::NightcoreTaiko(_) => GameModIntermode::Nightcore, - Self::HiddenTaiko(_) => GameModIntermode::Hidden, - Self::FlashlightTaiko(_) => GameModIntermode::Flashlight, - Self::AccuracyChallengeTaiko(_) => GameModIntermode::AccuracyChallenge, - Self::RandomTaiko(_) => GameModIntermode::Random, - Self::DifficultyAdjustTaiko(_) => GameModIntermode::DifficultyAdjust, - Self::ClassicTaiko(_) => GameModIntermode::Classic, - Self::SwapTaiko(_) => GameModIntermode::Swap, - Self::SingleTapTaiko(_) => GameModIntermode::SingleTap, - Self::ConstantSpeedTaiko(_) => GameModIntermode::ConstantSpeed, - Self::AutoplayTaiko(_) => GameModIntermode::Autoplay, - Self::CinemaTaiko(_) => GameModIntermode::Cinema, - Self::RelaxTaiko(_) => GameModIntermode::Relax, - Self::WindUpTaiko(_) => GameModIntermode::WindUp, - Self::WindDownTaiko(_) => GameModIntermode::WindDown, - Self::MutedTaiko(_) => GameModIntermode::Muted, - Self::AdaptiveSpeedTaiko(_) => GameModIntermode::AdaptiveSpeed, - Self::ScoreV2Taiko(_) => GameModIntermode::ScoreV2, - Self::EasyCatch(_) => GameModIntermode::Easy, - Self::NoFailCatch(_) => GameModIntermode::NoFail, - Self::HalfTimeCatch(_) => GameModIntermode::HalfTime, - Self::DaycoreCatch(_) => GameModIntermode::Daycore, - Self::HardRockCatch(_) => GameModIntermode::HardRock, - Self::SuddenDeathCatch(_) => GameModIntermode::SuddenDeath, - Self::PerfectCatch(_) => GameModIntermode::Perfect, - Self::DoubleTimeCatch(_) => GameModIntermode::DoubleTime, - Self::NightcoreCatch(_) => GameModIntermode::Nightcore, - Self::HiddenCatch(_) => GameModIntermode::Hidden, - Self::FlashlightCatch(_) => GameModIntermode::Flashlight, - Self::AccuracyChallengeCatch(_) => GameModIntermode::AccuracyChallenge, - Self::DifficultyAdjustCatch(_) => GameModIntermode::DifficultyAdjust, - Self::ClassicCatch(_) => GameModIntermode::Classic, - Self::MirrorCatch(_) => GameModIntermode::Mirror, - Self::AutoplayCatch(_) => GameModIntermode::Autoplay, - Self::CinemaCatch(_) => GameModIntermode::Cinema, - Self::RelaxCatch(_) => GameModIntermode::Relax, - Self::WindUpCatch(_) => GameModIntermode::WindUp, - Self::WindDownCatch(_) => GameModIntermode::WindDown, - Self::FloatingFruitsCatch(_) => GameModIntermode::FloatingFruits, - Self::MutedCatch(_) => GameModIntermode::Muted, - Self::NoScopeCatch(_) => GameModIntermode::NoScope, - Self::ScoreV2Catch(_) => GameModIntermode::ScoreV2, - Self::EasyMania(_) => GameModIntermode::Easy, - Self::NoFailMania(_) => GameModIntermode::NoFail, - Self::HalfTimeMania(_) => GameModIntermode::HalfTime, - Self::DaycoreMania(_) => GameModIntermode::Daycore, - Self::HardRockMania(_) => GameModIntermode::HardRock, - Self::SuddenDeathMania(_) => GameModIntermode::SuddenDeath, - Self::PerfectMania(_) => GameModIntermode::Perfect, - Self::DoubleTimeMania(_) => GameModIntermode::DoubleTime, - Self::NightcoreMania(_) => GameModIntermode::Nightcore, - Self::FadeInMania(_) => GameModIntermode::FadeIn, - Self::HiddenMania(_) => GameModIntermode::Hidden, - Self::CoverMania(_) => GameModIntermode::Cover, - Self::FlashlightMania(_) => GameModIntermode::Flashlight, - Self::AccuracyChallengeMania(_) => GameModIntermode::AccuracyChallenge, - Self::RandomMania(_) => GameModIntermode::Random, - Self::DualStagesMania(_) => GameModIntermode::DualStages, - Self::MirrorMania(_) => GameModIntermode::Mirror, - Self::DifficultyAdjustMania(_) => GameModIntermode::DifficultyAdjust, - Self::ClassicMania(_) => GameModIntermode::Classic, - Self::InvertMania(_) => GameModIntermode::Invert, - Self::ConstantSpeedMania(_) => GameModIntermode::ConstantSpeed, - Self::HoldOffMania(_) => GameModIntermode::HoldOff, - Self::OneKeyMania(_) => GameModIntermode::OneKey, - Self::TwoKeysMania(_) => GameModIntermode::TwoKeys, - Self::ThreeKeysMania(_) => GameModIntermode::ThreeKeys, - Self::FourKeysMania(_) => GameModIntermode::FourKeys, - Self::FiveKeysMania(_) => GameModIntermode::FiveKeys, - Self::SixKeysMania(_) => GameModIntermode::SixKeys, - Self::SevenKeysMania(_) => GameModIntermode::SevenKeys, - Self::EightKeysMania(_) => GameModIntermode::EightKeys, - Self::NineKeysMania(_) => GameModIntermode::NineKeys, - Self::TenKeysMania(_) => GameModIntermode::TenKeys, - Self::AutoplayMania(_) => GameModIntermode::Autoplay, - Self::CinemaMania(_) => GameModIntermode::Cinema, - Self::WindUpMania(_) => GameModIntermode::WindUp, - Self::WindDownMania(_) => GameModIntermode::WindDown, - Self::MutedMania(_) => GameModIntermode::Muted, - Self::AdaptiveSpeedMania(_) => GameModIntermode::AdaptiveSpeed, - Self::ScoreV2Mania(_) => GameModIntermode::ScoreV2, - Self::UnknownOsu(m) - | Self::UnknownTaiko(m) - | Self::UnknownCatch(m) - | Self::UnknownMania(m) => GameModIntermode::Unknown(*m), - } - } -} -impl PartialOrd for GameMod { - fn partial_cmp(&self, other: &Self) -> Option { - self.bits() - .zip(other.bits()) - .map(|(self_bits, other_bits)| self_bits.cmp(&other_bits)) - } -} -struct GameModSettings<'a> { - acronym: &'a str, - mode: GameMode, -} -impl<'de> DeserializeSeed<'de> for GameModSettings<'de> { - type Value = >::Value; - fn deserialize>(self, d: D) -> Result { - d.deserialize_any(self) - } -} -impl<'de> Visitor<'de> for GameModSettings<'de> { - type Value = GameMod; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("GameMod settings") - } - fn visit_map>(self, map: A) -> Result { - let d = MapAccessDeserializer::new(map); - let res = match (self.acronym, self.mode) { - ("EZ", GameMode::Osu) => GameMod::EasyOsu(Deserialize::deserialize(d)?), - ("NF", GameMode::Osu) => GameMod::NoFailOsu(Deserialize::deserialize(d)?), - ("HT", GameMode::Osu) => GameMod::HalfTimeOsu(Deserialize::deserialize(d)?), - ("DC", GameMode::Osu) => GameMod::DaycoreOsu(Deserialize::deserialize(d)?), - ("HR", GameMode::Osu) => GameMod::HardRockOsu(Deserialize::deserialize(d)?), - ("SD", GameMode::Osu) => GameMod::SuddenDeathOsu(Deserialize::deserialize(d)?), - ("PF", GameMode::Osu) => GameMod::PerfectOsu(Deserialize::deserialize(d)?), - ("DT", GameMode::Osu) => GameMod::DoubleTimeOsu(Deserialize::deserialize(d)?), - ("NC", GameMode::Osu) => GameMod::NightcoreOsu(Deserialize::deserialize(d)?), - ("HD", GameMode::Osu) => GameMod::HiddenOsu(Deserialize::deserialize(d)?), - ("FL", GameMode::Osu) => GameMod::FlashlightOsu(Deserialize::deserialize(d)?), - ("BL", GameMode::Osu) => GameMod::BlindsOsu(Deserialize::deserialize(d)?), - ("ST", GameMode::Osu) => GameMod::StrictTrackingOsu(Deserialize::deserialize(d)?), - ("AC", GameMode::Osu) => GameMod::AccuracyChallengeOsu(Deserialize::deserialize(d)?), - ("TP", GameMode::Osu) => GameMod::TargetPracticeOsu(Deserialize::deserialize(d)?), - ("DA", GameMode::Osu) => GameMod::DifficultyAdjustOsu(Deserialize::deserialize(d)?), - ("CL", GameMode::Osu) => GameMod::ClassicOsu(Deserialize::deserialize(d)?), - ("RD", GameMode::Osu) => GameMod::RandomOsu(Deserialize::deserialize(d)?), - ("MR", GameMode::Osu) => GameMod::MirrorOsu(Deserialize::deserialize(d)?), - ("AL", GameMode::Osu) => GameMod::AlternateOsu(Deserialize::deserialize(d)?), - ("SG", GameMode::Osu) => GameMod::SingleTapOsu(Deserialize::deserialize(d)?), - ("AT", GameMode::Osu) => GameMod::AutoplayOsu(Deserialize::deserialize(d)?), - ("CN", GameMode::Osu) => GameMod::CinemaOsu(Deserialize::deserialize(d)?), - ("RX", GameMode::Osu) => GameMod::RelaxOsu(Deserialize::deserialize(d)?), - ("AP", GameMode::Osu) => GameMod::AutopilotOsu(Deserialize::deserialize(d)?), - ("SO", GameMode::Osu) => GameMod::SpunOutOsu(Deserialize::deserialize(d)?), - ("TR", GameMode::Osu) => GameMod::TransformOsu(Deserialize::deserialize(d)?), - ("WG", GameMode::Osu) => GameMod::WiggleOsu(Deserialize::deserialize(d)?), - ("SI", GameMode::Osu) => GameMod::SpinInOsu(Deserialize::deserialize(d)?), - ("GR", GameMode::Osu) => GameMod::GrowOsu(Deserialize::deserialize(d)?), - ("DF", GameMode::Osu) => GameMod::DeflateOsu(Deserialize::deserialize(d)?), - ("WU", GameMode::Osu) => GameMod::WindUpOsu(Deserialize::deserialize(d)?), - ("WD", GameMode::Osu) => GameMod::WindDownOsu(Deserialize::deserialize(d)?), - ("TC", GameMode::Osu) => GameMod::TraceableOsu(Deserialize::deserialize(d)?), - ("BR", GameMode::Osu) => GameMod::BarrelRollOsu(Deserialize::deserialize(d)?), - ("AD", GameMode::Osu) => GameMod::ApproachDifferentOsu(Deserialize::deserialize(d)?), - ("MU", GameMode::Osu) => GameMod::MutedOsu(Deserialize::deserialize(d)?), - ("NS", GameMode::Osu) => GameMod::NoScopeOsu(Deserialize::deserialize(d)?), - ("MG", GameMode::Osu) => GameMod::MagnetisedOsu(Deserialize::deserialize(d)?), - ("RP", GameMode::Osu) => GameMod::RepelOsu(Deserialize::deserialize(d)?), - ("AS", GameMode::Osu) => GameMod::AdaptiveSpeedOsu(Deserialize::deserialize(d)?), - ("FR", GameMode::Osu) => GameMod::FreezeFrameOsu(Deserialize::deserialize(d)?), - ("BU", GameMode::Osu) => GameMod::BubblesOsu(Deserialize::deserialize(d)?), - ("SY", GameMode::Osu) => GameMod::SynesthesiaOsu(Deserialize::deserialize(d)?), - ("DP", GameMode::Osu) => GameMod::DepthOsu(Deserialize::deserialize(d)?), - ("TD", GameMode::Osu) => GameMod::TouchDeviceOsu(Deserialize::deserialize(d)?), - ("SV2", GameMode::Osu) => GameMod::ScoreV2Osu(Deserialize::deserialize(d)?), - ("EZ", GameMode::Taiko) => GameMod::EasyTaiko(Deserialize::deserialize(d)?), - ("NF", GameMode::Taiko) => GameMod::NoFailTaiko(Deserialize::deserialize(d)?), - ("HT", GameMode::Taiko) => GameMod::HalfTimeTaiko(Deserialize::deserialize(d)?), - ("DC", GameMode::Taiko) => GameMod::DaycoreTaiko(Deserialize::deserialize(d)?), - ("HR", GameMode::Taiko) => GameMod::HardRockTaiko(Deserialize::deserialize(d)?), - ("SD", GameMode::Taiko) => GameMod::SuddenDeathTaiko(Deserialize::deserialize(d)?), - ("PF", GameMode::Taiko) => GameMod::PerfectTaiko(Deserialize::deserialize(d)?), - ("DT", GameMode::Taiko) => GameMod::DoubleTimeTaiko(Deserialize::deserialize(d)?), - ("NC", GameMode::Taiko) => GameMod::NightcoreTaiko(Deserialize::deserialize(d)?), - ("HD", GameMode::Taiko) => GameMod::HiddenTaiko(Deserialize::deserialize(d)?), - ("FL", GameMode::Taiko) => GameMod::FlashlightTaiko(Deserialize::deserialize(d)?), - ("AC", GameMode::Taiko) => { - GameMod::AccuracyChallengeTaiko(Deserialize::deserialize(d)?) - } - ("RD", GameMode::Taiko) => GameMod::RandomTaiko(Deserialize::deserialize(d)?), - ("DA", GameMode::Taiko) => GameMod::DifficultyAdjustTaiko(Deserialize::deserialize(d)?), - ("CL", GameMode::Taiko) => GameMod::ClassicTaiko(Deserialize::deserialize(d)?), - ("SW", GameMode::Taiko) => GameMod::SwapTaiko(Deserialize::deserialize(d)?), - ("SG", GameMode::Taiko) => GameMod::SingleTapTaiko(Deserialize::deserialize(d)?), - ("CS", GameMode::Taiko) => GameMod::ConstantSpeedTaiko(Deserialize::deserialize(d)?), - ("AT", GameMode::Taiko) => GameMod::AutoplayTaiko(Deserialize::deserialize(d)?), - ("CN", GameMode::Taiko) => GameMod::CinemaTaiko(Deserialize::deserialize(d)?), - ("RX", GameMode::Taiko) => GameMod::RelaxTaiko(Deserialize::deserialize(d)?), - ("WU", GameMode::Taiko) => GameMod::WindUpTaiko(Deserialize::deserialize(d)?), - ("WD", GameMode::Taiko) => GameMod::WindDownTaiko(Deserialize::deserialize(d)?), - ("MU", GameMode::Taiko) => GameMod::MutedTaiko(Deserialize::deserialize(d)?), - ("AS", GameMode::Taiko) => GameMod::AdaptiveSpeedTaiko(Deserialize::deserialize(d)?), - ("SV2", GameMode::Taiko) => GameMod::ScoreV2Taiko(Deserialize::deserialize(d)?), - ("EZ", GameMode::Catch) => GameMod::EasyCatch(Deserialize::deserialize(d)?), - ("NF", GameMode::Catch) => GameMod::NoFailCatch(Deserialize::deserialize(d)?), - ("HT", GameMode::Catch) => GameMod::HalfTimeCatch(Deserialize::deserialize(d)?), - ("DC", GameMode::Catch) => GameMod::DaycoreCatch(Deserialize::deserialize(d)?), - ("HR", GameMode::Catch) => GameMod::HardRockCatch(Deserialize::deserialize(d)?), - ("SD", GameMode::Catch) => GameMod::SuddenDeathCatch(Deserialize::deserialize(d)?), - ("PF", GameMode::Catch) => GameMod::PerfectCatch(Deserialize::deserialize(d)?), - ("DT", GameMode::Catch) => GameMod::DoubleTimeCatch(Deserialize::deserialize(d)?), - ("NC", GameMode::Catch) => GameMod::NightcoreCatch(Deserialize::deserialize(d)?), - ("HD", GameMode::Catch) => GameMod::HiddenCatch(Deserialize::deserialize(d)?), - ("FL", GameMode::Catch) => GameMod::FlashlightCatch(Deserialize::deserialize(d)?), - ("AC", GameMode::Catch) => { - GameMod::AccuracyChallengeCatch(Deserialize::deserialize(d)?) - } - ("DA", GameMode::Catch) => GameMod::DifficultyAdjustCatch(Deserialize::deserialize(d)?), - ("CL", GameMode::Catch) => GameMod::ClassicCatch(Deserialize::deserialize(d)?), - ("MR", GameMode::Catch) => GameMod::MirrorCatch(Deserialize::deserialize(d)?), - ("AT", GameMode::Catch) => GameMod::AutoplayCatch(Deserialize::deserialize(d)?), - ("CN", GameMode::Catch) => GameMod::CinemaCatch(Deserialize::deserialize(d)?), - ("RX", GameMode::Catch) => GameMod::RelaxCatch(Deserialize::deserialize(d)?), - ("WU", GameMode::Catch) => GameMod::WindUpCatch(Deserialize::deserialize(d)?), - ("WD", GameMode::Catch) => GameMod::WindDownCatch(Deserialize::deserialize(d)?), - ("FF", GameMode::Catch) => GameMod::FloatingFruitsCatch(Deserialize::deserialize(d)?), - ("MU", GameMode::Catch) => GameMod::MutedCatch(Deserialize::deserialize(d)?), - ("NS", GameMode::Catch) => GameMod::NoScopeCatch(Deserialize::deserialize(d)?), - ("SV2", GameMode::Catch) => GameMod::ScoreV2Catch(Deserialize::deserialize(d)?), - ("EZ", GameMode::Mania) => GameMod::EasyMania(Deserialize::deserialize(d)?), - ("NF", GameMode::Mania) => GameMod::NoFailMania(Deserialize::deserialize(d)?), - ("HT", GameMode::Mania) => GameMod::HalfTimeMania(Deserialize::deserialize(d)?), - ("DC", GameMode::Mania) => GameMod::DaycoreMania(Deserialize::deserialize(d)?), - ("HR", GameMode::Mania) => GameMod::HardRockMania(Deserialize::deserialize(d)?), - ("SD", GameMode::Mania) => GameMod::SuddenDeathMania(Deserialize::deserialize(d)?), - ("PF", GameMode::Mania) => GameMod::PerfectMania(Deserialize::deserialize(d)?), - ("DT", GameMode::Mania) => GameMod::DoubleTimeMania(Deserialize::deserialize(d)?), - ("NC", GameMode::Mania) => GameMod::NightcoreMania(Deserialize::deserialize(d)?), - ("FI", GameMode::Mania) => GameMod::FadeInMania(Deserialize::deserialize(d)?), - ("HD", GameMode::Mania) => GameMod::HiddenMania(Deserialize::deserialize(d)?), - ("CO", GameMode::Mania) => GameMod::CoverMania(Deserialize::deserialize(d)?), - ("FL", GameMode::Mania) => GameMod::FlashlightMania(Deserialize::deserialize(d)?), - ("AC", GameMode::Mania) => { - GameMod::AccuracyChallengeMania(Deserialize::deserialize(d)?) - } - ("RD", GameMode::Mania) => GameMod::RandomMania(Deserialize::deserialize(d)?), - ("DS", GameMode::Mania) => GameMod::DualStagesMania(Deserialize::deserialize(d)?), - ("MR", GameMode::Mania) => GameMod::MirrorMania(Deserialize::deserialize(d)?), - ("DA", GameMode::Mania) => GameMod::DifficultyAdjustMania(Deserialize::deserialize(d)?), - ("CL", GameMode::Mania) => GameMod::ClassicMania(Deserialize::deserialize(d)?), - ("IN", GameMode::Mania) => GameMod::InvertMania(Deserialize::deserialize(d)?), - ("CS", GameMode::Mania) => GameMod::ConstantSpeedMania(Deserialize::deserialize(d)?), - ("HO", GameMode::Mania) => GameMod::HoldOffMania(Deserialize::deserialize(d)?), - ("1K", GameMode::Mania) => GameMod::OneKeyMania(Deserialize::deserialize(d)?), - ("2K", GameMode::Mania) => GameMod::TwoKeysMania(Deserialize::deserialize(d)?), - ("3K", GameMode::Mania) => GameMod::ThreeKeysMania(Deserialize::deserialize(d)?), - ("4K", GameMode::Mania) => GameMod::FourKeysMania(Deserialize::deserialize(d)?), - ("5K", GameMode::Mania) => GameMod::FiveKeysMania(Deserialize::deserialize(d)?), - ("6K", GameMode::Mania) => GameMod::SixKeysMania(Deserialize::deserialize(d)?), - ("7K", GameMode::Mania) => GameMod::SevenKeysMania(Deserialize::deserialize(d)?), - ("8K", GameMode::Mania) => GameMod::EightKeysMania(Deserialize::deserialize(d)?), - ("9K", GameMode::Mania) => GameMod::NineKeysMania(Deserialize::deserialize(d)?), - ("10K", GameMode::Mania) => GameMod::TenKeysMania(Deserialize::deserialize(d)?), - ("AT", GameMode::Mania) => GameMod::AutoplayMania(Deserialize::deserialize(d)?), - ("CN", GameMode::Mania) => GameMod::CinemaMania(Deserialize::deserialize(d)?), - ("WU", GameMode::Mania) => GameMod::WindUpMania(Deserialize::deserialize(d)?), - ("WD", GameMode::Mania) => GameMod::WindDownMania(Deserialize::deserialize(d)?), - ("MU", GameMode::Mania) => GameMod::MutedMania(Deserialize::deserialize(d)?), - ("AS", GameMode::Mania) => GameMod::AdaptiveSpeedMania(Deserialize::deserialize(d)?), - ("SV2", GameMode::Mania) => GameMod::ScoreV2Mania(Deserialize::deserialize(d)?), - _ => { - let acronym = ::from_str(self.acronym) - .map_err(DeError::custom)?; - // All fields are specified already but we still want to clear - // out content from the deserializer. - #[allow(clippy::needless_update)] - let unknown = UnknownMod { - acronym, - ..Deserialize::deserialize(d)? - }; - match self.mode { - GameMode::Osu => GameMod::UnknownOsu(unknown), - GameMode::Taiko => GameMod::UnknownTaiko(unknown), - GameMode::Catch => GameMod::UnknownCatch(unknown), - GameMode::Mania => GameMod::UnknownMania(unknown), - } - } - }; - Ok(res) - } -} -impl<'de> Visitor<'de> for ModeAsSeed { - type Value = GameMod; - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("a GameMod") - } - fn visit_str(self, v: &str) -> Result { - Ok(GameMod::new(v, self.mode)) - } - fn visit_map>(self, mut map: A) -> Result { - // Using RawValue avoids an allocation since serde_json generally - // deserializes into String to handle escaped characters. - let key = map.next_key::<&RawValue>()?.map(RawValue::get); - let Some(r#""acronym""#) = key else { - return Err(DeError::custom("expected `acronym` as first field")); - }; - let acronym: &'de str = map.next_value()?; - let mut gamemod = None; - while let Some(key) = map.next_key::<&str>()? { - if key == "settings" { - gamemod = Some(map.next_value_seed(GameModSettings { - acronym, - mode: self.mode, - })?); - } else { - let _: IgnoredAny = map.next_value()?; - } - } - Ok(gamemod.unwrap_or_else(|| GameMod::new(acronym, self.mode))) - } -} -#[cfg(feature = "serialize")] -impl serde::Serialize for GameMod { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeMap; - let mut s = s.serialize_map(None)?; - s.serialize_entry("acronym", self.acronym().as_str())?; - match self { - Self::EasyOsu(m) => { - let has_some = m.retries.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::HalfTimeOsu(m) => { - let has_some = m.speed_change.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DaycoreOsu(m) => { - let has_some = m.speed_change.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::SuddenDeathOsu(m) => { - let has_some = m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::PerfectOsu(m) => { - let has_some = m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DoubleTimeOsu(m) => { - let has_some = m.speed_change.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::NightcoreOsu(m) => { - let has_some = m.speed_change.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::HiddenOsu(m) => { - let has_some = m.only_fade_approach_circles.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::FlashlightOsu(m) => { - let has_some = m.follow_delay.is_some() - || m.size_multiplier.is_some() - || m.combo_based_size.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::AccuracyChallengeOsu(m) => { - let has_some = m.minimum_accuracy.is_some() - || m.accuracy_judge_mode.is_some() - || m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::TargetPracticeOsu(m) => { - let has_some = m.seed.is_some() || m.metronome.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DifficultyAdjustOsu(m) => { - let has_some = m.circle_size.is_some() - || m.approach_rate.is_some() - || m.drain_rate.is_some() - || m.overall_difficulty.is_some() - || m.extended_limits.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::ClassicOsu(m) => { - let has_some = m.no_slider_head_accuracy.is_some() - || m.classic_note_lock.is_some() - || m.always_play_tail_sample.is_some() - || m.fade_hit_circle_early.is_some() - || m.classic_health.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::RandomOsu(m) => { - let has_some = m.angle_sharpness.is_some() || m.seed.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::MirrorOsu(m) => { - let has_some = m.reflection.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::WiggleOsu(m) => { - let has_some = m.strength.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::GrowOsu(m) => { - let has_some = m.start_scale.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DeflateOsu(m) => { - let has_some = m.start_scale.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::WindUpOsu(m) => { - let has_some = - m.initial_rate.is_some() || m.final_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::WindDownOsu(m) => { - let has_some = - m.initial_rate.is_some() || m.final_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::BarrelRollOsu(m) => { - let has_some = m.spin_speed.is_some() || m.direction.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::ApproachDifferentOsu(m) => { - let has_some = m.scale.is_some() || m.style.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::MutedOsu(m) => { - let has_some = m.inverse_muting.is_some() - || m.enable_metronome.is_some() - || m.mute_combo_count.is_some() - || m.affects_hit_sounds.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::NoScopeOsu(m) => { - let has_some = m.hidden_combo_count.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::MagnetisedOsu(m) => { - let has_some = m.attraction_strength.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::RepelOsu(m) => { - let has_some = m.repulsion_strength.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::AdaptiveSpeedOsu(m) => { - let has_some = m.initial_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DepthOsu(m) => { - let has_some = m.max_depth.is_some() || m.show_approach_circles.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::HalfTimeTaiko(m) => { - let has_some = m.speed_change.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DaycoreTaiko(m) => { - let has_some = m.speed_change.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::SuddenDeathTaiko(m) => { - let has_some = m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::PerfectTaiko(m) => { - let has_some = m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DoubleTimeTaiko(m) => { - let has_some = m.speed_change.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::NightcoreTaiko(m) => { - let has_some = m.speed_change.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::FlashlightTaiko(m) => { - let has_some = m.size_multiplier.is_some() || m.combo_based_size.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::AccuracyChallengeTaiko(m) => { - let has_some = m.minimum_accuracy.is_some() - || m.accuracy_judge_mode.is_some() - || m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::RandomTaiko(m) => { - let has_some = m.seed.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DifficultyAdjustTaiko(m) => { - let has_some = m.scroll_speed.is_some() - || m.drain_rate.is_some() - || m.overall_difficulty.is_some() - || m.extended_limits.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::WindUpTaiko(m) => { - let has_some = - m.initial_rate.is_some() || m.final_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::WindDownTaiko(m) => { - let has_some = - m.initial_rate.is_some() || m.final_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::MutedTaiko(m) => { - let has_some = m.inverse_muting.is_some() - || m.enable_metronome.is_some() - || m.mute_combo_count.is_some() - || m.affects_hit_sounds.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::AdaptiveSpeedTaiko(m) => { - let has_some = m.initial_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::EasyCatch(m) => { - let has_some = m.retries.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::HalfTimeCatch(m) => { - let has_some = m.speed_change.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DaycoreCatch(m) => { - let has_some = m.speed_change.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::SuddenDeathCatch(m) => { - let has_some = m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::PerfectCatch(m) => { - let has_some = m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DoubleTimeCatch(m) => { - let has_some = m.speed_change.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::NightcoreCatch(m) => { - let has_some = m.speed_change.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::FlashlightCatch(m) => { - let has_some = m.size_multiplier.is_some() || m.combo_based_size.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::AccuracyChallengeCatch(m) => { - let has_some = m.minimum_accuracy.is_some() - || m.accuracy_judge_mode.is_some() - || m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DifficultyAdjustCatch(m) => { - let has_some = m.circle_size.is_some() - || m.approach_rate.is_some() - || m.hard_rock_offsets.is_some() - || m.drain_rate.is_some() - || m.overall_difficulty.is_some() - || m.extended_limits.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::WindUpCatch(m) => { - let has_some = - m.initial_rate.is_some() || m.final_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::WindDownCatch(m) => { - let has_some = - m.initial_rate.is_some() || m.final_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::MutedCatch(m) => { - let has_some = m.inverse_muting.is_some() - || m.enable_metronome.is_some() - || m.mute_combo_count.is_some() - || m.affects_hit_sounds.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::NoScopeCatch(m) => { - let has_some = m.hidden_combo_count.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::EasyMania(m) => { - let has_some = m.retries.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::HalfTimeMania(m) => { - let has_some = m.speed_change.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DaycoreMania(m) => { - let has_some = m.speed_change.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::SuddenDeathMania(m) => { - let has_some = m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::PerfectMania(m) => { - let has_some = m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DoubleTimeMania(m) => { - let has_some = m.speed_change.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::NightcoreMania(m) => { - let has_some = m.speed_change.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::CoverMania(m) => { - let has_some = m.coverage.is_some() || m.direction.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::FlashlightMania(m) => { - let has_some = m.size_multiplier.is_some() || m.combo_based_size.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::AccuracyChallengeMania(m) => { - let has_some = m.minimum_accuracy.is_some() - || m.accuracy_judge_mode.is_some() - || m.restart.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::RandomMania(m) => { - let has_some = m.seed.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::DifficultyAdjustMania(m) => { - let has_some = m.drain_rate.is_some() - || m.overall_difficulty.is_some() - || m.extended_limits.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::WindUpMania(m) => { - let has_some = - m.initial_rate.is_some() || m.final_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::WindDownMania(m) => { - let has_some = - m.initial_rate.is_some() || m.final_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::MutedMania(m) => { - let has_some = m.inverse_muting.is_some() - || m.enable_metronome.is_some() - || m.mute_combo_count.is_some() - || m.affects_hit_sounds.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - Self::AdaptiveSpeedMania(m) => { - let has_some = m.initial_rate.is_some() || m.adjust_pitch.is_some(); - if has_some { - s.serialize_entry("settings", m)?; - } - } - _ => {} - } - s.end() - } -} -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! mods_inner { - ( [ $( $mode:ident )? ] 10K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* TenKeys ) - }; - ( [ $( $mode:ident )? ] 1K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* OneKey ) - }; - ( [ $( $mode:ident )? ] 2K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* TwoKeys ) - }; - ( [ $( $mode:ident )? ] 3K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* ThreeKeys ) - }; - ( [ $( $mode:ident )? ] 4K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* FourKeys ) - }; - ( [ $( $mode:ident )? ] 5K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* FiveKeys ) - }; - ( [ $( $mode:ident )? ] 6K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* SixKeys ) - }; - ( [ $( $mode:ident )? ] 7K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* SevenKeys ) - }; - ( [ $( $mode:ident )? ] 8K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* EightKeys ) - }; - ( [ $( $mode:ident )? ] 9K $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* NineKeys ) - }; - ( [ $( $mode:ident )? ] AC $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* AccuracyChallenge ) - }; - ( [ $( $mode:ident )? ] AD $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* ApproachDifferent ) - }; - ( [ $( $mode:ident )? ] AL $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Alternate ) - }; - ( [ $( $mode:ident )? ] AP $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Autopilot ) - }; - ( [ $( $mode:ident )? ] AS $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* AdaptiveSpeed ) - }; - ( [ $( $mode:ident )? ] AT $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Autoplay ) - }; - ( [ $( $mode:ident )? ] BL $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Blinds ) - }; - ( [ $( $mode:ident )? ] BR $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* BarrelRoll ) - }; - ( [ $( $mode:ident )? ] BU $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Bubbles ) - }; - ( [ $( $mode:ident )? ] CL $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Classic ) - }; - ( [ $( $mode:ident )? ] CN $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Cinema ) - }; - ( [ $( $mode:ident )? ] CO $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Cover ) - }; - ( [ $( $mode:ident )? ] CS $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* ConstantSpeed ) - }; - ( [ $( $mode:ident )? ] DA $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* DifficultyAdjust ) - }; - ( [ $( $mode:ident )? ] DC $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Daycore ) - }; - ( [ $( $mode:ident )? ] DF $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Deflate ) - }; - ( [ $( $mode:ident )? ] DP $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Depth ) - }; - ( [ $( $mode:ident )? ] DS $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* DualStages ) - }; - ( [ $( $mode:ident )? ] DT $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* DoubleTime ) - }; - ( [ $( $mode:ident )? ] EZ $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Easy ) - }; - ( [ $( $mode:ident )? ] FF $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* FloatingFruits ) - }; - ( [ $( $mode:ident )? ] FI $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* FadeIn ) - }; - ( [ $( $mode:ident )? ] FL $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Flashlight ) - }; - ( [ $( $mode:ident )? ] FR $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* FreezeFrame ) - }; - ( [ $( $mode:ident )? ] GR $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Grow ) - }; - ( [ $( $mode:ident )? ] HD $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Hidden ) - }; - ( [ $( $mode:ident )? ] HO $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* HoldOff ) - }; - ( [ $( $mode:ident )? ] HR $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* HardRock ) - }; - ( [ $( $mode:ident )? ] HT $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* HalfTime ) - }; - ( [ $( $mode:ident )? ] IN $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Invert ) - }; - ( [ $( $mode:ident )? ] MG $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Magnetised ) - }; - ( [ $( $mode:ident )? ] MR $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Mirror ) - }; - ( [ $( $mode:ident )? ] MU $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Muted ) - }; - ( [ $( $mode:ident )? ] NC $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Nightcore ) - }; - ( [ $( $mode:ident )? ] NF $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* NoFail ) - }; - ( [ $( $mode:ident )? ] NS $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* NoScope ) - }; - ( [ $( $mode:ident )? ] PF $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Perfect ) - }; - ( [ $( $mode:ident )? ] RD $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Random ) - }; - ( [ $( $mode:ident )? ] RP $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Repel ) - }; - ( [ $( $mode:ident )? ] RX $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Relax ) - }; - ( [ $( $mode:ident )? ] SD $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* SuddenDeath ) - }; - ( [ $( $mode:ident )? ] SG $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* SingleTap ) - }; - ( [ $( $mode:ident )? ] SI $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* SpinIn ) - }; - ( [ $( $mode:ident )? ] SO $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* SpunOut ) - }; - ( [ $( $mode:ident )? ] ST $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* StrictTracking ) - }; - ( [ $( $mode:ident )? ] SV2 $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* ScoreV2 ) - }; - ( [ $( $mode:ident )? ] SW $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Swap ) - }; - ( [ $( $mode:ident )? ] SY $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Synesthesia ) - }; - ( [ $( $mode:ident )? ] TC $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Traceable ) - }; - ( [ $( $mode:ident )? ] TD $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* TouchDevice ) - }; - ( [ $( $mode:ident )? ] TP $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* TargetPractice ) - }; - ( [ $( $mode:ident )? ] TR $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Transform ) - }; - ( [ $( $mode:ident )? ] WD $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* WindDown ) - }; - ( [ $( $mode:ident )? ] WG $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* Wiggle ) - }; - ( [ $( $mode:ident )? ] WU $( $rest:tt )* ) => { - mods_inner!( [ $( $mode )? ] $( $rest )* WindUp ) - }; - ( [ $mode:ident ] ) => {{ - let _ = $crate::model::GameMode::$mode; - $crate::model::mods::GameMods::new() - }}; - ( [ $mode:ident ] $( $name:ident )* ) => { - paste::paste! {{ - #[allow(unused_mut)] - let mut mods = $crate::model::mods::GameMods::new(); - $( mods.insert($crate::model::mods::GameMod::[<$name $mode>](Default::default())); )* - mods - }} - }; - ( [] $( $name:ident )* ) => {{ - #[allow(unused_mut)] - let mut mods = $crate::model::mods::GameModsIntermode::new(); - $( mods.insert($crate::model::mods::GameModIntermode::$name); )* - mods - }}; -} diff --git a/rosu-v2/src/model/mods/intermode.rs b/rosu-v2/src/model/mods/intermode.rs deleted file mode 100644 index 487506c..0000000 --- a/rosu-v2/src/model/mods/intermode.rs +++ /dev/null @@ -1,863 +0,0 @@ -use std::{ - borrow::Cow, - cmp::Ordering, - collections::BTreeSet, - convert::Infallible, - fmt::{Debug, Display, Formatter, Result as FmtResult}, - ops::{BitOr, BitOrAssign, Sub, SubAssign}, - str::FromStr, -}; - -use serde::{ - de::{Error as DeError, SeqAccess, Visitor}, - Deserialize, Deserializer, -}; - -use crate::prelude::{DoubleTimeOsu, GameMode, NightcoreOsu, PerfectOsu, SuddenDeathOsu}; - -use super::{ - intersection::{GameModsIntermodeIntersection, IntersectionInner}, - iter::{GameModsIntermodeIter, IntoGameModsIntermodeIter}, - Acronym, GameMod, GameModIntermode, GameMods, -}; - -/// Combination of [`GameModIntermode`]s. -#[derive(Clone, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize), serde(transparent))] -pub struct GameModsIntermode { - inner: BTreeSet, -} - -impl GameModsIntermode { - /// Returns empty mods i.e. "NoMod" - #[inline] - pub fn new() -> Self { - Self::default() - } - - /// Return the accumulated bit values of all contained mods. - /// - /// Mods that don't have bit values will be ignored. - /// See - /// - /// # Example - /// ```rust - /// use rosu_v2::mods; - /// - /// let hdhrdtwu = mods!(HD HR DT WU); - /// assert_eq!(hdhrdtwu.bits(), 8 + 16 + 64); - /// ``` - #[inline] - pub fn bits(&self) -> u32 { - self.inner - .iter() - .copied() - .flat_map(GameModIntermode::bits) - .fold(0, u32::bitor) - } - - /// Return the accumulated bit values of all contained mods. - /// - /// If any contained mod has no bit value `None` is returned. - /// See - /// - /// # Example - /// ```rust - /// use rosu_v2::mods; - /// - /// let hdhrdt = mods!(HD HR DT); - /// assert_eq!(hdhrdt.checked_bits(), Some(8 + 16 + 64)); - /// - /// let hdhrdtwu = mods!(HD HR DT WU); - /// assert_eq!(hdhrdtwu.checked_bits(), None); - /// ``` - #[inline] - pub fn checked_bits(&self) -> Option { - self.inner - .iter() - .copied() - .map(GameModIntermode::bits) - .try_fold(0, |bits, next| Some(next? | bits)) - } - - /// Returns `true` if no mods are contained. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{GameModIntermode, GameModsIntermode}; - /// - /// let mut mods = GameModsIntermode::new(); - /// assert!(mods.is_empty()); - /// - /// mods.insert(GameModIntermode::Hidden); - /// assert!(!mods.is_empty()); - /// ``` - #[inline] - pub fn is_empty(&self) -> bool { - self.inner.is_empty() - } - - /// Returns the amount of contained mods. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, GameModIntermode, GameModsIntermode}; - /// - /// let hdhrdt = mods!(HD HR DT); - /// assert_eq!(hdhrdt.len(), 3); - /// - /// let mut nm = GameModsIntermode::new(); - /// assert_eq!(nm.len(), 0); - /// assert_eq!(nm.to_string(), "NM"); - /// ``` - #[inline] - pub fn len(&self) -> usize { - self.inner.len() - } - - /// Add a [`GameModIntermode`] - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{GameModIntermode, GameModsIntermode}; - /// - /// let mut mods = GameModsIntermode::new(); - /// assert_eq!(mods.to_string(), "NM"); - /// - /// mods.insert(GameModIntermode::Traceable); - /// assert_eq!(mods.to_string(), "TC"); - /// - /// mods.insert(GameModIntermode::HardRock); - /// assert_eq!(mods.to_string(), "HRTC"); - /// ``` - #[inline] - pub fn insert(&mut self, gamemod: GameModIntermode) { - self.inner.insert(gamemod); - } - - /// Check whether a given mod is contained. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, GameModIntermode}; - /// - /// let hd = mods!(HD); - /// assert!(hd.contains(GameModIntermode::Hidden)); - /// assert!(!hd.contains(GameModIntermode::HardRock)); - /// ``` - #[inline] - pub fn contains(&self, gamemod: M) -> bool - where - GameModIntermode: From, - { - self.inner.contains(&GameModIntermode::from(gamemod)) - } - - /// Check whether a given [`Acronym`] is contained. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, Acronym}; - /// - /// let nc = mods!(NC); - /// assert!(nc.contains_acronym("NC".parse::().unwrap())); - /// assert!(!nc.contains_acronym("DT".parse::().unwrap())); - /// ``` - #[inline] - pub fn contains_acronym(&self, acronym: Acronym) -> bool { - self.inner - .iter() - .any(|gamemod| gamemod.acronym() == acronym) - } - - /// Remove a gamemod and return whether it was contained. - /// - /// # Example - /// ``` - /// use rosu_v2::prelude::{mods, GameModIntermode, GameModsIntermode}; - /// - /// let mut mods: GameModsIntermode = mods!(HD HR); - /// - /// assert!(mods.remove(GameModIntermode::Hidden)); - /// assert_eq!(mods.to_string(), "HR"); - /// assert!(!mods.remove(GameModIntermode::DoubleTime)); - /// ``` - #[inline] - pub fn remove(&mut self, gamemod: M) -> bool - where - GameModIntermode: From, - { - self.inner.remove(&GameModIntermode::from(gamemod)) - } - - /// Remove all mods contained in the iterator. - /// - /// # Example - /// ``` - /// use rosu_v2::prelude::{mods, GameModIntermode, GameModsIntermode}; - /// - /// let mut mods: GameModsIntermode = mods!(HD HR WG DT BR); - /// - /// mods.remove_all([GameModIntermode::Hidden, GameModIntermode::Easy]); - /// assert_eq!(mods.to_string(), "HRDTBRWG"); - /// - /// mods.remove_all(mods!(NF WG)); - /// assert_eq!(mods.to_string(), "HRDTBR") - /// ``` - #[inline] - pub fn remove_all(&mut self, mods: I) - where - I: IntoIterator, - GameModIntermode: From, - { - for gamemod in mods { - self.remove(gamemod); - } - } - - /// Parse bitflags into [`GameModsIntermode`] - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, GameModsIntermode}; - /// - /// let bits = 8 + 64 + 512 + 1024; - /// assert_eq!(GameModsIntermode::from_bits(bits), mods!(FL HD NC)) - /// ``` - pub fn from_bits(mut bits: u32) -> Self { - struct BitIterator(u32); - - impl Iterator for BitIterator { - type Item = bool; - - fn next(&mut self) -> Option { - if self.0 == 0 { - None - } else { - let bit = self.0 & 0b1; - self.0 >>= 1; - - Some(bit == 1) - } - } - - fn size_hint(&self) -> (usize, Option) { - ((self.0 > 0) as usize, None) - } - } - - // Special handling for NC and PF since they require two bits - bits &= if (bits & NightcoreOsu::bits()) == NightcoreOsu::bits() { - !DoubleTimeOsu::bits() - } else { - !(1 << 9) - }; - - bits &= if (bits & PerfectOsu::bits()) == PerfectOsu::bits() { - !SuddenDeathOsu::bits() - } else { - !(1 << 14) - }; - - const BITFLAG_MODS: [GameModIntermode; 31] = [ - GameModIntermode::NoFail, - GameModIntermode::Easy, - GameModIntermode::TouchDevice, - GameModIntermode::Hidden, - GameModIntermode::HardRock, - GameModIntermode::SuddenDeath, - GameModIntermode::DoubleTime, - GameModIntermode::Relax, - GameModIntermode::HalfTime, - GameModIntermode::Nightcore, - GameModIntermode::Flashlight, - GameModIntermode::Autoplay, - GameModIntermode::SpunOut, - GameModIntermode::Autopilot, - GameModIntermode::Perfect, - GameModIntermode::FourKeys, - GameModIntermode::FiveKeys, - GameModIntermode::SixKeys, - GameModIntermode::SevenKeys, - GameModIntermode::EightKeys, - GameModIntermode::FadeIn, - GameModIntermode::Random, - GameModIntermode::Cinema, - GameModIntermode::TargetPractice, - GameModIntermode::NineKeys, - GameModIntermode::DualStages, - GameModIntermode::OneKey, - GameModIntermode::ThreeKeys, - GameModIntermode::TwoKeys, - GameModIntermode::ScoreV2, - GameModIntermode::Mirror, - ]; - - let inner = BitIterator(bits) - .zip(BITFLAG_MODS) - .filter_map(|(is_set, gamemod)| is_set.then_some(gamemod)) - .collect(); - - Self { inner } - } - - /// Try to parse a combination of mod acronyms into [`GameModsIntermode`]. - /// - /// Returns `None` if an unknown acronym was encountered. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::GameModsIntermode; - /// - /// let hdhrwu = GameModsIntermode::try_from_acronyms("HRWUHD").unwrap(); - /// assert_eq!(hdhrwu.to_string(), "HDHRWU"); - /// - /// assert!(GameModsIntermode::try_from_acronyms("QQQ").is_none()); - /// ``` - pub fn try_from_acronyms(s: &str) -> Option { - let uppercased = to_uppercase(s); - - if uppercased == "NM" { - return Some(Self::new()); - } - - // We currently don't allow a gamemod to have an acronym of length 1 - if s.len() == 1 { - return None; - } - - let mut remaining = uppercased.as_ref(); - let mut mods = BTreeSet::new(); - - while !remaining.is_empty() { - // Split off the first two characters and check if it's an acronym - let (candidate, rest) = split_prefix::<2>(remaining); - - // SAFETY: `candidate` is guaranteed to be of length 2 and has been capitalized - let acronym = unsafe { Acronym::from_str_unchecked(candidate) }; - let gamemod = GameModIntermode::from_acronym(acronym); - - if !matches!(gamemod, GameModIntermode::Unknown(_)) && rest.len() != 1 { - mods.insert(gamemod); - remaining = rest; - - continue; - } - - // Repeat for the first three characters - let (candidate, rest) = split_prefix::<3>(remaining); - - // SAFETY: `candidate` is guaranteed to be of length 3 and has been capitalized - let acronym = unsafe { Acronym::from_str_unchecked(candidate) }; - let gamemod = GameModIntermode::from_acronym(acronym); - - if matches!(gamemod, GameModIntermode::Unknown(_)) { - return None; - } - - mods.insert(gamemod); - remaining = rest; - } - - Some(Self { inner: mods }) - } - - /// Parse a combination of mod acronyms into [`GameModsIntermode`]. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::GameModsIntermode; - /// - /// let hdhrwu = GameModsIntermode::from_acronyms("HRWUHD"); - /// assert_eq!(hdhrwu.len(), 3); - /// assert_eq!(hdhrwu.to_string(), "HDHRWU"); - /// - /// let mut iter = GameModsIntermode::from_acronyms("QQhdQ").into_iter(); - /// assert_eq!(iter.next().unwrap().to_string(), "HDQ"); // unknown mod - /// assert_eq!(iter.next().unwrap().to_string(), "QQ"); // unknown mod - /// assert!(iter.next().is_none()); - /// ``` - pub fn from_acronyms(s: &str) -> Self { - let uppercased = to_uppercase(s); - - if uppercased == "NM" { - return Self::new(); - } - - let mut mods = BTreeSet::new(); - - // We currently don't allow a gamemod to have an acronym of length 1 - let mut remaining = if s.len() == 1 { - mods.insert(GameModIntermode::Unknown(Default::default())); - - "" - } else { - uppercased.as_ref() - }; - - while !remaining.is_empty() { - // Split off the first two characters and check if it's an acronym - let (candidate, rest) = split_prefix::<2>(remaining); - - // SAFETY: `candidate` is guaranteed to be of length 2 and has been capitalized - let acronym = unsafe { Acronym::from_str_unchecked(candidate) }; - let gamemod = GameModIntermode::from_acronym(acronym); - - if !matches!(gamemod, GameModIntermode::Unknown(_)) && rest.len() != 1 { - mods.insert(gamemod); - remaining = rest; - - continue; - } - - // Repeat for the first three characters - let (candidate, three_letter_rest) = split_prefix::<3>(remaining); - - // SAFETY: `candidate` is guaranteed to be of length 3 and has been capitalized - let acronym = unsafe { Acronym::from_str_unchecked(candidate) }; - let three_letter_gamemod = GameModIntermode::from_acronym(acronym); - - if !matches!(three_letter_gamemod, GameModIntermode::Unknown(_)) - || three_letter_rest.is_empty() - { - mods.insert(three_letter_gamemod); - remaining = three_letter_rest; - } else { - mods.insert(gamemod); - remaining = rest; - } - } - - Self { inner: mods } - } - - /// Returns an iterator over all mods that appear in both [`GameModsIntermode`]. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, GameModIntermode}; - /// - /// let hd = mods!(HD); - /// let hdhr = mods!(HD HR); - /// let mut intersection = hd.intersection(&hdhr); - /// assert_eq!(intersection.next(), Some(GameModIntermode::Hidden)); - /// assert_eq!(intersection.next(), None); - /// ``` - // https://github.com/rust-lang/rust/blob/c1d3610ac1ddd1cd605479274047fd0a3f37d220/library/alloc/src/collections/btree/set.rs#L517 - pub fn intersection<'m>( - &'m self, - other: &'m GameModsIntermode, - ) -> GameModsIntermodeIntersection<'m> { - let (self_min, self_max) = - if let (Some(self_min), Some(self_max)) = (self.inner.first(), self.inner.last()) { - (*self_min, *self_max) - } else { - return GameModsIntermodeIntersection { - inner: IntersectionInner::Answer(None), - }; - }; - - let (other_min, other_max) = - if let (Some(other_min), Some(other_max)) = (other.inner.first(), other.inner.last()) { - (*other_min, *other_max) - } else { - return GameModsIntermodeIntersection { - inner: IntersectionInner::Answer(None), - }; - }; - - GameModsIntermodeIntersection { - inner: match (self_min.cmp(&other_max), self_max.cmp(&other_min)) { - (Ordering::Greater, _) | (_, Ordering::Less) => IntersectionInner::Answer(None), - (Ordering::Equal, _) => IntersectionInner::Answer(Some(self_min)), - (_, Ordering::Equal) => IntersectionInner::Answer(Some(self_max)), - _ => IntersectionInner::new_stitch(self.inner.iter(), other.inner.iter()), - }, - } - } - - /// Check whether the two [`GameMods`] have any common mods. - /// - /// # Example - /// ```rust - /// use rosu_v2::mods; - /// - /// let hd = mods!(HD); - /// assert!(!hd.intersects(&mods!(HR))); - /// assert!(hd.intersects(&mods!(HD HR))); - /// ``` - #[inline] - pub fn intersects(&self, other: &Self) -> bool { - self.intersection(other).next().is_some() - } - - /// The legacy clock rate of the [`GameModsIntermode`]. - /// - /// Looks for the first occurrence of DT, NC, HT, or DC - /// and returns `1.5`, `0.75`, or `1.0` accordingly. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, GameModIntermode}; - /// - /// let hd = mods!(HD); - /// assert_eq!(hd.legacy_clock_rate(), 1.0); - /// - /// let mut hddt = hd; - /// hddt.insert(GameModIntermode::DoubleTime); - /// assert_eq!(hddt.legacy_clock_rate(), 1.5); - /// ``` - #[inline] - pub fn legacy_clock_rate(&self) -> f32 { - if self.inner.contains(&GameModIntermode::DoubleTime) - || self.inner.contains(&GameModIntermode::Nightcore) - { - 1.5 - } else if self.inner.contains(&GameModIntermode::HalfTime) - || self.inner.contains(&GameModIntermode::Daycore) - { - 0.75 - } else { - 1.0 - } - } - - /// Returns an iterator over all contained mods. - /// - /// Note that the iterator will immediately yield `None` in case of "NoMod". - pub fn iter(&self) -> GameModsIntermodeIter<'_> { - GameModsIntermodeIter::new(self.inner.iter().copied()) - } - - /// Tries to turn a [`GameModsIntermode`] into a [`GameMods`]. - /// - /// Returns `None` if any contained [`GameModIntermode`] is unknown for the - /// given [`GameMode`]. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, GameMods, GameMode}; - /// - /// let dtfi: GameMods = mods!(DT FI).try_with_mode(GameMode::Mania).unwrap(); - /// - /// // The FadeIn mod doesn't exist in Taiko - /// assert!(mods!(DT FI).try_with_mode(GameMode::Taiko).is_none()); - /// ``` - pub fn try_with_mode(self, mode: GameMode) -> Option { - self.inner - .into_iter() - .map(|gamemod| GameMod::new(gamemod.acronym().as_str(), mode)) - .try_fold(GameMods::default(), |mut mods, next| { - if matches!( - next, - GameMod::UnknownOsu(_) - | GameMod::UnknownTaiko(_) - | GameMod::UnknownCatch(_) - | GameMod::UnknownMania(_) - ) { - None - } else { - mods.insert(next); - - Some(mods) - } - }) - } - - /// Turn a [`GameModsIntermode`] into a [`GameMods`]. - /// - /// Any contained [`GameModIntermode`] that's unknown for the given - /// [`GameMode`] will be replaced with `GameModIntermode::Unknown`. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, GameMods, GameMode}; - /// - /// let dtfi: GameMods = mods!(DT FI).with_mode(GameMode::Mania); - /// - /// // The FadeIn mod doesn't exist in Taiko - /// let dt_unknown: GameMods = mods!(DT FI).with_mode(GameMode::Taiko); - /// assert_eq!(dt_unknown.to_string(), "DTFI"); - /// ``` - pub fn with_mode(self, mode: GameMode) -> GameMods { - self.inner - .into_iter() - .map(|gamemod| GameMod::new(gamemod.acronym().as_str(), mode)) - .collect() - } -} - -impl Debug for GameModsIntermode { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - Debug::fmt(&self.inner, f) - } -} - -impl Display for GameModsIntermode { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - if self.is_empty() { - f.write_str("NM") - } else { - for gamemod in self.iter() { - f.write_str(gamemod.acronym().as_str())?; - } - - Ok(()) - } - } -} - -impl IntoIterator for GameModsIntermode { - type Item = GameModIntermode; - type IntoIter = IntoGameModsIntermodeIter; - - /// Turns [`GameModsIntermode`] into an iterator over all contained mods. - /// - /// Note that the iterator will immediately yield `None` in case of "NoMod". - fn into_iter(self) -> Self::IntoIter { - IntoGameModsIntermodeIter::new(self.inner.into_iter()) - } -} - -impl FromIterator for GameModsIntermode -where - GameModIntermode: From, -{ - fn from_iter>(iter: T) -> Self { - Self { - inner: iter.into_iter().map(GameModIntermode::from).collect(), - } - } -} - -impl Extend for GameModsIntermode -where - GameModIntermode: From, -{ - fn extend>(&mut self, iter: T) { - self.inner - .extend(iter.into_iter().map(GameModIntermode::from)) - } -} - -impl BitOr for GameModsIntermode { - type Output = Self; - - /// Adds a [`GameModIntermode`] to the [`GameModsIntermode`]. - fn bitor(mut self, rhs: GameModIntermode) -> Self::Output { - self |= rhs; - - self - } -} - -impl BitOrAssign for GameModsIntermode { - /// Adds a [`GameModIntermode`] to the [`GameModsIntermode`]. - fn bitor_assign(&mut self, rhs: GameModIntermode) { - self.insert(rhs); - } -} - -impl Sub for GameModsIntermode { - type Output = Self; - - /// Removes a [`GameModIntermode`] from the [`GameModsIntermode`] - fn sub(mut self, rhs: GameModIntermode) -> Self::Output { - self -= rhs; - - self - } -} - -impl SubAssign for GameModsIntermode { - /// Removes a [`GameModIntermode`] from the [`GameModsIntermode`] - fn sub_assign(&mut self, rhs: GameModIntermode) { - self.remove(rhs); - } -} - -impl<'de> Deserialize<'de> for GameModsIntermode { - fn deserialize>(d: D) -> Result { - struct GameModsIntermodeVisitor; - - impl<'de> Visitor<'de> for GameModsIntermodeVisitor { - type Value = GameModsIntermode; - - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("integer bitflags, mod acronyms, or a sequence of mod acronyms") - } - - fn visit_u64(self, v: u64) -> Result { - u32::try_from(v) - .map_err(|_| DeError::custom("GameModsIntermode bitflags must fit in a u32")) - .map(GameModsIntermode::from_bits) - } - - fn visit_str(self, v: &str) -> Result { - Ok(GameModsIntermode::from_acronyms(v)) - } - - fn visit_seq>(self, mut seq: A) -> Result { - let mut inner = BTreeSet::new(); - - while let Some(elem) = seq.next_element()? { - let acronym = Acronym::from_str(elem).map_err(DeError::custom)?; - inner.insert(GameModIntermode::from_acronym(acronym)); - } - - Ok(GameModsIntermode { inner }) - } - } - - d.deserialize_any(GameModsIntermodeVisitor) - } -} - -impl From for GameModsIntermode { - fn from(mods: GameMods) -> Self { - Self { - inner: mods.inner.values().map(GameMod::intermode).collect(), - } - } -} - -impl From for GameModsIntermode { - fn from(gamemod: GameModIntermode) -> Self { - let mut mods = Self::new(); - mods.insert(gamemod); - - mods - } -} - -impl FromStr for GameModsIntermode { - type Err = Infallible; - - fn from_str(s: &str) -> Result { - Ok(Self::from_acronyms(s)) - } -} - -/// Splits the first `N` characters off -fn split_prefix(s: &str) -> (&str, &str) { - let end_idx = s - .char_indices() - .nth(N - 1) - .map_or_else(|| s.len(), |(idx, c)| idx + c.len_utf8()); - - s.split_at(end_idx) -} - -/// Put a `&str` into ASCII uppercase. Doesn't allocate if it already is uppercase. -fn to_uppercase(s: &str) -> Cow<'_, str> { - match s.char_indices().find(|(_, c)| c.is_ascii_lowercase()) { - Some((pos, _)) => { - let mut output = s.to_owned(); - - // SAFETY: `char_indices` is guaranteed to provide a valid index - unsafe { output.get_unchecked_mut(pos..) }.make_ascii_uppercase(); - - Cow::Owned(output) - } - None => Cow::Borrowed(s), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn push() { - let mut mods = mods!(); - mods.insert(GameModIntermode::HardRock); - mods.insert(GameModIntermode::Wiggle); - - assert_eq!(mods.len(), 2); - assert_eq!(mods.to_string(), "HRWG"); - } - - #[test] - fn from_bits_nomod() { - assert!(GameModsIntermode::from_bits(0).is_empty()); - } - - #[test] - fn from_bits_valid() { - assert_eq!(GameModsIntermode::from_bits(8 + 64 + 512), mods!(NC HD)); - } - - #[test] - fn from_bits_invalid_nightcore() { - assert_eq!(GameModsIntermode::from_bits(512), GameModsIntermode::new()); - } - - #[test] - fn from_str_nonempty() { - let mods: GameModsIntermode = "TCWGFLWU".parse().unwrap(); - assert_eq!(mods, mods!(FL TC WG WU)); - } - - #[test] - fn from_str_unknown() { - let mut iter = "YYQQQ".parse::().unwrap().into_iter(); - - // Since acronyms of length 1 are not valid, it picks the last three - // characters. - // Also, "QQQ" comes before "YY" to it'll be the first mod. - assert_eq!(iter.next().unwrap().to_string(), "QQQ"); - assert_eq!(iter.next().unwrap().to_string(), "YY"); - assert!(iter.next().is_none()); - } - - #[test] - fn contains() { - let mods = mods!(HD HR NC); - assert!(mods.contains(GameModIntermode::Nightcore)); - assert!(mods.contains(GameModIntermode::Hidden)); - assert!(!mods.contains(GameModIntermode::DoubleTime)); - } - - #[test] - fn checked_bits() { - let mods = mods!(HD TC DT); - assert_eq!(mods.checked_bits(), None); - } - - #[test] - fn unchecked_bits() { - let mods = mods!(TC DT HD); - assert_eq!(mods.bits(), 72); - } - - #[test] - fn intersection() { - let a = mods!(HD WU HR); - let b = mods!(WU CL HR); - let mut intersection = a.intersection(&b); - assert_eq!(intersection.next(), Some(GameModIntermode::HardRock)); - assert_eq!(intersection.next(), Some(GameModIntermode::WindUp)); - assert_eq!(intersection.next(), None); - } - - #[test] - fn deser_str() { - let json = r#""HDHRWG""#; - let mods = serde_json::from_str::(json).unwrap(); - assert_eq!(mods, mods!(HD HR WG)); - } - - #[test] - fn deser_bits() { - let json = r#"1096"#; - let mods = serde_json::from_str::(json).unwrap(); - assert_eq!(mods, mods!(HD DT FL)); - } - - #[test] - fn deser_seq() { - let json = r#"["WU", "BL", "EZ"]"#; - let mods = serde_json::from_str::(json).unwrap(); - assert_eq!(mods, mods!(BL EZ WU)); - } -} diff --git a/rosu-v2/src/model/mods/intersection.rs b/rosu-v2/src/model/mods/intersection.rs deleted file mode 100644 index 7e48513..0000000 --- a/rosu-v2/src/model/mods/intersection.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::{ - cmp::{min, Ordering}, - collections::{btree_map::Iter as TreeIter, btree_set::Iter as SetIter}, -}; - -use super::{GameMod, GameModIntermode, GameModOrder}; - -pub(super) enum IntersectionInner { - Stitch(Stitch), - Answer(Option), -} - -impl IntersectionInner { - pub(super) const fn new_stitch(a: I, b: I) -> Self { - Self::Stitch(Stitch { a, b }) - } -} - -pub(super) struct Stitch { - a: I, - b: I, -} - -/// Iterator over [`GameMod`] references that appear in both given [`GameMods`](crate::prelude::GameMods). -// https://github.com/rust-lang/rust/blob/c1d3610ac1ddd1cd605479274047fd0a3f37d220/library/alloc/src/collections/btree/set.rs#L256 -pub struct GameModsIntersection<'m> { - pub(super) inner: IntersectionInner, &'m GameMod>, -} - -impl<'m> Iterator for GameModsIntersection<'m> { - type Item = &'m GameMod; - - #[inline] - fn next(&mut self) -> Option { - match &mut self.inner { - IntersectionInner::Stitch(Stitch { a, b }) => { - let mut a_next = a.next()?; - let mut b_next = b.next()?; - - loop { - match a_next.0.cmp(b_next.0) { - Ordering::Less => a_next = a.next()?, - Ordering::Greater => b_next = b.next()?, - Ordering::Equal => return Some(a_next.1), - } - } - } - IntersectionInner::Answer(answer) => answer.take(), - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - match &self.inner { - IntersectionInner::Stitch(Stitch { a, b }) => (0, Some(min(a.len(), b.len()))), - IntersectionInner::Answer(None) => (0, Some(0)), - IntersectionInner::Answer(Some(_)) => (1, Some(1)), - } - } - - #[inline] - fn min(mut self) -> Option { - self.next() - } -} - -/// Iterator over [`GameModIntermode`]s that appear in both given [`GameModsIntermode`](crate::prelude::GameModsIntermode). -pub struct GameModsIntermodeIntersection<'m> { - pub(super) inner: IntersectionInner, GameModIntermode>, -} - -impl Iterator for GameModsIntermodeIntersection<'_> { - type Item = GameModIntermode; - - #[inline] - fn next(&mut self) -> Option { - match &mut self.inner { - IntersectionInner::Stitch(Stitch { a, b }) => { - let mut a_next = a.next()?; - let mut b_next = b.next()?; - - loop { - match a_next.cmp(b_next) { - Ordering::Less => a_next = a.next()?, - Ordering::Greater => b_next = b.next()?, - Ordering::Equal => return Some(*a_next), - } - } - } - IntersectionInner::Answer(answer) => answer.take(), - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - match &self.inner { - IntersectionInner::Stitch(Stitch { a, b }) => (0, Some(min(a.len(), b.len()))), - IntersectionInner::Answer(None) => (0, Some(0)), - IntersectionInner::Answer(Some(_)) => (1, Some(1)), - } - } - - #[inline] - fn min(mut self) -> Option { - self.next() - } -} diff --git a/rosu-v2/src/model/mods/iter.rs b/rosu-v2/src/model/mods/iter.rs deleted file mode 100644 index 0e641c1..0000000 --- a/rosu-v2/src/model/mods/iter.rs +++ /dev/null @@ -1,98 +0,0 @@ -use std::{ - collections::{ - btree_map::{IntoValues, Values, ValuesMut}, - btree_set::{IntoIter, Iter}, - }, - fmt::{Debug, Formatter, Result as FmtResult}, - iter::{Copied, FusedIterator}, -}; - -use super::{GameMod, GameModIntermode, GameModOrder}; - -macro_rules! mods_iter { - ( - $( #[$meta:meta] )* - $name:ident $( < $outer_lifetime:lifetime > )? : - $inner:ident < $( $inner_generic:tt ),+ > => - $item:ty - ) => { - $( #[ $meta ] )* - pub struct $name $( < $outer_lifetime > )? { - inner: $inner < $( $inner_generic ),* >, - } - - impl $( < $outer_lifetime > )? $name $( < $outer_lifetime > )? { - pub(super) const fn new(inner: $inner < $( $inner_generic ),* >) -> Self { - Self { inner } - } - } - - impl $( < $outer_lifetime > )? Debug for $name $( < $outer_lifetime > )? { - #[inline] - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - Debug::fmt(&self.inner, f) - } - } - - impl $( < $outer_lifetime > )? Iterator for $name $( < $outer_lifetime > )? { - type Item = $item; - - #[inline] - fn next(&mut self) -> Option { - self.inner.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - - #[inline] - fn last(mut self) -> Option { - self.inner.next_back() - } - } - - impl $( < $outer_lifetime > )? DoubleEndedIterator for $name $( < $outer_lifetime > )? { - #[inline] - fn next_back(&mut self) -> Option { - self.inner.next_back() - } - } - - impl $( < $outer_lifetime > )? ExactSizeIterator for $name $( < $outer_lifetime > )? { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } - } - - impl $( < $outer_lifetime > )? FusedIterator for $name $( < $outer_lifetime > )? {} - }; -} - -mods_iter! { - #[derive(Clone)] - #[doc = "Iterates over [`GameMod`] references"] - GameModsIter<'m>: Values<'m, GameModOrder, GameMod> => &'m GameMod -} -mods_iter! { - #[doc = "Iterates over mutable [`GameMod`] references"] - GameModsIterMut<'m>: ValuesMut<'m, GameModOrder, GameMod> => &'m mut GameMod -} -mods_iter! { - #[doc = "Iterates over [`GameMod`]"] - IntoGameModsIter: IntoValues => GameMod -} - -type GameModsIntermodeIterInner<'m> = Copied>; - -mods_iter! { - #[derive(Clone)] - #[doc = "Iterates over [`GameModIntermode`]"] - GameModsIntermodeIter<'m>: GameModsIntermodeIterInner<'m> => GameModIntermode -} -mods_iter! { - #[doc = "Iterates over [`GameModIntermode`]"] - IntoGameModsIntermodeIter: IntoIter => GameModIntermode -} diff --git a/rosu-v2/src/model/mods/macros.rs b/rosu-v2/src/model/mods/macros.rs deleted file mode 100644 index 41851d8..0000000 --- a/rosu-v2/src/model/mods/macros.rs +++ /dev/null @@ -1,80 +0,0 @@ -/// Short-hand macro to easily create [`GameMods`](crate::model::mods::GameMods) -/// or [`GameModsIntermode`](crate::model::mods::GameModsIntermode). -/// -/// To create [`GameModsIntermode`](crate::model::mods::GameModsIntermode), -/// specify a space-separated list of acronyms. -/// -/// To create [`GameMods`](crate::model::mods::GameMods), -/// specify `Osu`, `Taiko`, `Catch`, or `Mania`, followed -/// by a colon (`:`), followed by a space-separated list of acronyms. -/// Note that creating [`GameMods`](crate::model::mods::GameMods) requires the `macros` feature flag. -/// -/// # Example -/// -/// ```rust -/// # use rosu_v2::{mods, model::mods::GameModsIntermode}; -#[cfg_attr(feature = "macros", doc = "# use rosu_v2::model::mods::GameMods;")] -#[cfg_attr(feature = "macros", doc = "let mods: GameMods = mods!(Taiko: NC HR);")] -#[cfg_attr(feature = "macros", doc = r#"assert_eq!(mods.to_string(), "HRNC");"#)] // FIXME: seems to not be rendered properly by rustdoc -#[cfg_attr(feature = "macros", doc = "")] -/// let mods: GameModsIntermode = mods!(DT HR TC); -/// assert_eq!(mods.to_string(), "HRDTTC"); -/// ``` -#[macro_export(local_inner_macros)] -macro_rules! mods { - ( $mode:ident: $first:ident $( $rest:ident )* ) => {{ - #[cfg(not(feature = "macros"))] - { - std::compile_error!("must enable `macros` feature to use `mods!` macro for a GameMode"); - - Default::default() - } - - #[cfg(feature = "macros")] - mods_inner!([$mode] $first $( $rest )* ) - }}; - - ( Osu ) => { mods_inner!( [ Osu ] ) }; - ( Taiko ) => { mods_inner!( [ Taiko ] ) }; - ( Catch ) => { mods_inner!( [ Catch ] ) }; - ( Mania ) => { mods_inner!( [ Mania ] ) }; - ( ) => { mods_inner!([]) }; - - ( $first:ident $( $rest:ident )* ) => { - mods_inner!([] $first $( $rest )* ) - }; -} - -#[cfg(test)] -mod tests { - #[test] - fn empty_intermode() { - let mods = mods!(); - assert!(mods.is_empty()) - } - - #[test] - fn single_intermode() { - let mods = mods!(WG); - assert_eq!(mods.len(), 1); - } - - #[test] - fn full_intermode() { - let mods = mods!(HD DT DT HR TC); - assert_eq!(mods.to_string(), "HDHRDTTC"); - } - - #[test] - fn empty_catch() { - let mods = mods!(Catch); - assert!(mods.is_empty()); - } - - #[cfg(feature = "macros")] - #[test] - fn full_taiko() { - let mods = mods!(Taiko: HR PF); - assert_eq!(mods.len(), 2); - } -} diff --git a/rosu-v2/src/model/mods/manual.rs b/rosu-v2/src/model/mods/manual.rs deleted file mode 100644 index 9e0a5e1..0000000 --- a/rosu-v2/src/model/mods/manual.rs +++ /dev/null @@ -1,47 +0,0 @@ -use super::GameMod; - -impl GameMod { - /// The clock rate of the [`GameMod`] - /// - /// Returns `None` if there is no single clock rate. - pub const fn clock_rate(&self) -> Option { - // TODO: replace with `Option::unwrap_or` when it's const stable - const fn unwrap_or(opt: Option, default: f32) -> f32 { - match opt { - Some(n) => n, - None => default, - } - } - - match self { - Self::DoubleTimeOsu(m) => Some(unwrap_or(m.speed_change, 1.5)), - Self::DoubleTimeTaiko(m) => Some(unwrap_or(m.speed_change, 1.5)), - Self::DoubleTimeCatch(m) => Some(unwrap_or(m.speed_change, 1.5)), - Self::DoubleTimeMania(m) => Some(unwrap_or(m.speed_change, 1.5)), - Self::NightcoreOsu(m) => Some(unwrap_or(m.speed_change, 1.5)), - Self::NightcoreTaiko(m) => Some(unwrap_or(m.speed_change, 1.5)), - Self::NightcoreCatch(m) => Some(unwrap_or(m.speed_change, 1.5)), - Self::NightcoreMania(m) => Some(unwrap_or(m.speed_change, 1.5)), - Self::HalfTimeOsu(m) => Some(unwrap_or(m.speed_change, 0.75)), - Self::HalfTimeTaiko(m) => Some(unwrap_or(m.speed_change, 0.75)), - Self::HalfTimeCatch(m) => Some(unwrap_or(m.speed_change, 0.75)), - Self::HalfTimeMania(m) => Some(unwrap_or(m.speed_change, 0.75)), - Self::DaycoreOsu(m) => Some(unwrap_or(m.speed_change, 0.75)), - Self::DaycoreTaiko(m) => Some(unwrap_or(m.speed_change, 0.75)), - Self::DaycoreCatch(m) => Some(unwrap_or(m.speed_change, 0.75)), - Self::DaycoreMania(m) => Some(unwrap_or(m.speed_change, 0.75)), - Self::WindUpOsu(_) => None, - Self::WindUpTaiko(_) => None, - Self::WindUpCatch(_) => None, - Self::WindUpMania(_) => None, - Self::WindDownOsu(_) => None, - Self::WindDownTaiko(_) => None, - Self::WindDownCatch(_) => None, - Self::WindDownMania(_) => None, - Self::AdaptiveSpeedOsu(_) => None, - Self::AdaptiveSpeedTaiko(_) => None, - Self::AdaptiveSpeedMania(_) => None, - _ => Some(1.0), - } - } -} diff --git a/rosu-v2/src/model/mods/mod.rs b/rosu-v2/src/model/mods/mod.rs deleted file mode 100644 index e808de2..0000000 --- a/rosu-v2/src/model/mods/mod.rs +++ /dev/null @@ -1,847 +0,0 @@ -use std::{ - cmp::Ordering, - collections::BTreeMap, - fmt::{Debug, Display, Formatter, Result as FmtResult}, - iter::FromIterator, - ops::BitOr, -}; - -#[macro_use] -mod macros; - -mod acronym; -mod generated_mods; -mod intermode; -mod intersection; -mod iter; -mod manual; -mod mode_as_seed; - -pub use self::{ - acronym::Acronym, - generated_mods::*, - intermode::GameModsIntermode, - intersection::{GameModsIntermodeIntersection, GameModsIntersection}, - iter::{ - GameModsIntermodeIter, GameModsIter, GameModsIterMut, IntoGameModsIntermodeIter, - IntoGameModsIter, - }, - mode_as_seed::ModeAsSeed, -}; - -use self::intersection::IntersectionInner; - -use super::GameMode; - -/// Combination of [`GameMod`]s. -#[derive(Clone, Default, PartialEq)] -pub struct GameMods { - inner: BTreeMap, -} - -impl GameMods { - /// Returns empty mods i.e. "NoMod" - #[inline] - pub fn new() -> Self { - Self::default() - } - - /// Return the accumulated bit values of all contained mods. - /// - /// Mods that don't have bit values will be ignored. - /// See - /// - /// # Example - /// ```rust - /// # use rosu_v2::prelude::{GameMod, GameMods}; - /// # let hdhrdtwu: GameMods = [ - /// # GameMod::HiddenOsu(Default::default()), - /// # GameMod::HardRockOsu(Default::default()), - /// # GameMod::DoubleTimeOsu(Default::default()), - /// # GameMod::WindUpOsu(Default::default()), - /// # ].into_iter().collect(); - /// # /* - /// let hdhrdtwu = mods!(Osu: HD HR DT WU); - /// # */ - /// assert_eq!(hdhrdtwu.bits(), 8 + 16 + 64); - /// ``` - #[inline] - pub fn bits(&self) -> u32 { - self.inner - .values() - .flat_map(GameMod::bits) - .fold(0, u32::bitor) - } - - /// Return the accumulated bit values of all contained mods. - /// - /// If any contained mod has no bit value `None` is returned. - /// See - /// - /// # Example - /// ```rust - /// # use rosu_v2::prelude::{GameMod, GameMods}; - /// # let hdhrdt: GameMods = [ - /// # GameMod::HiddenOsu(Default::default()), - /// # GameMod::HardRockOsu(Default::default()), - /// # GameMod::DoubleTimeOsu(Default::default()), - /// # ].into_iter().collect(); - /// # let hdhrdtwu: GameMods = [ - /// # GameMod::HiddenOsu(Default::default()), - /// # GameMod::HardRockOsu(Default::default()), - /// # GameMod::DoubleTimeOsu(Default::default()), - /// # GameMod::WindUpOsu(Default::default()), - /// # ].into_iter().collect(); - /// # /* - /// let hdhrdt = mods!(Osu: HD HR DT); - /// # */ - /// assert_eq!(hdhrdt.checked_bits(), Some(8 + 16 + 64)); - /// - /// # /* - /// let hdhrdtwu = mods!(Osu: HD HR DT WU); - /// # */ - /// assert_eq!(hdhrdtwu.checked_bits(), None); - /// ``` - #[inline] - pub fn checked_bits(&self) -> Option { - self.inner - .values() - .map(GameMod::bits) - .try_fold(0, |bits, next| Some(next? | bits)) - } - - /// Returns `true` if no mods are contained. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{GameMod, GameMods}; - /// - /// let mut mods = GameMods::new(); - /// assert!(mods.is_empty()); - /// - /// mods.insert(GameMod::HiddenOsu(Default::default())); - /// assert!(!mods.is_empty()); - /// ``` - #[inline] - pub fn is_empty(&self) -> bool { - self.inner.is_empty() - } - - /// Returns the amount of contained mods. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{GameMod, GameMods}; - /// - /// # let hdhrdt: GameMods = [ - /// # GameMod::HiddenCatch(Default::default()), - /// # GameMod::HardRockCatch(Default::default()), - /// # GameMod::DoubleTimeCatch(Default::default()), - /// # ].into_iter().collect(); - /// # /* - /// let hdhrdt = mods!(Catch: HD HR DT); - /// # */ - /// assert_eq!(hdhrdt.len(), 3); - /// - /// let mut nm = GameMods::new(); - /// assert_eq!(nm.len(), 0); - /// assert_eq!(nm.to_string(), "NM"); - /// ``` - #[inline] - pub fn len(&self) -> usize { - self.inner.len() - } - - /// Add a [`GameMod`] - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{GameMod, GameMods}; - /// - /// let mut mods = GameMods::new(); - /// assert_eq!(mods.to_string(), "NM"); - /// - /// mods.insert(GameMod::TraceableOsu(Default::default())); - /// assert_eq!(mods.to_string(), "TC"); - /// - /// mods.insert(GameMod::HardRockOsu(Default::default())); - /// assert_eq!(mods.to_string(), "HRTC"); - /// ``` - #[inline] - pub fn insert(&mut self, gamemod: GameMod) { - self.inner.insert(GameModOrder::from(&gamemod), gamemod); - } - - /// Check whether a given [`GameMod`] is contained. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::GameMod; - /// - /// # let hd = rosu_v2::prelude::GameMods::from(GameMod::HiddenTaiko(Default::default())); - /// # /* - /// let hd = mods!(Taiko: HD); - /// # */ - /// assert!(hd.contains(&GameMod::HiddenTaiko(Default::default()))); - /// assert!(!hd.contains(&GameMod::HiddenOsu(Default::default()))); - /// ``` - #[inline] - pub fn contains(&self, gamemod: &GameMod) -> bool { - self.inner.contains_key(&GameModOrder::from(gamemod)) - } - - /// Check whether a given [`GameModIntermode`] is contained. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::GameModIntermode; - /// - /// # let hd = rosu_v2::prelude::GameMods::from(rosu_v2::prelude::GameMod::HiddenTaiko(Default::default())); - /// # /* - /// let hd = mods!(Taiko: HD); - /// # */ - /// assert!(hd.contains_intermode(GameModIntermode::Hidden)); - /// assert!(!hd.contains_intermode(GameModIntermode::HardRock)); - /// ``` - #[inline] - pub fn contains_intermode(&self, gamemod: M) -> bool - where - GameModIntermode: From, - { - self.inner.contains_key(&GameModIntermode::from(gamemod)) - } - - /// Check whether any of the given mods are contained. - /// - /// Note that this method does not consider the mods' modes so it could - /// return `true` even if it's a different mode. - /// - /// # Example - /// ```rust - /// use rosu_v2::mods; - /// - /// # use rosu_v2::prelude::{GameMod, GameMods}; - /// # let hd = GameMods::from(GameMod::HiddenTaiko(Default::default())); - /// # /* - /// let hd = mods!(Taiko: HD); - /// # */ - /// - /// assert!(hd.contains_any(mods!(HD HR))); - /// assert!(!hd.contains_any(mods!(HR DT))); - /// - /// // Careful: It returns `true` even if it's a different mode - /// # assert!(hd.contains_any(GameMods::from(GameMod::HiddenOsu(Default::default())))); - /// # /* - /// assert!(hd.contains_any(mods!(Osu: HD))); - /// # */ - /// ``` - #[inline] - pub fn contains_any(&self, mods: I) -> bool - where - I: IntoIterator, - GameModIntermode: From, - { - mods.into_iter() - .any(|gamemod| self.contains_intermode(gamemod)) - } - - /// Check whether a given [`Acronym`] is contained. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::Acronym; - /// - /// # use rosu_v2::prelude::{GameMod, GameMods}; - /// # let mods: GameMods = [ - /// # GameMod::NoFailOsu(Default::default()), - /// # GameMod::DoubleTimeOsu(Default::default()), - /// # ].into_iter().collect(); - /// # /* - /// let mods = mods!(Osu: NF DT); - /// # */ - /// - /// let nf = "NF".parse::().unwrap(); - /// assert!(mods.contains_acronym(nf)); - /// - /// let hd = "HD".parse::().unwrap(); - /// assert!(!mods.contains_acronym(hd)); - /// ``` - #[inline] - pub fn contains_acronym(&self, acronym: Acronym) -> bool { - self.inner - .values() - .any(|gamemod| gamemod.acronym() == acronym) - || (self.is_empty() && acronym.as_str() == "NM") - } - - /// Remove a [`GameMod`] and return whether it was contained. - /// - /// # Example - /// ``` - /// use rosu_v2::prelude::{GameMod, GameMods}; - /// - /// # let mut mods: GameMods = [ - /// # GameMod::DoubleTimeMania(Default::default()), - /// # GameMod::MirrorMania(Default::default()) - /// # ].into_iter().collect(); - /// # /* - /// let mut mods: GameMods = mods!(Mania: DT MR); - /// #*/ - /// - /// assert!(mods.remove(&GameMod::MirrorMania(Default::default()))); - /// assert_eq!(mods.to_string(), "DT"); - /// assert!(!mods.remove(&GameMod::DoubleTimeCatch(Default::default()))); - /// ``` - #[inline] - pub fn remove(&mut self, gamemod: &GameMod) -> bool { - self.inner.remove(&GameModOrder::from(gamemod)).is_some() - } - - /// Remove a gamemod and return whether it was contained. - /// - /// If the same gamemod is contained for multiple modes, only one of them will be removed. - /// - /// # Example - /// ``` - /// use rosu_v2::prelude::{mods, GameModIntermode, GameMod, GameMods}; - /// - /// let mut mods: GameMods = [ - /// GameMod::HiddenOsu(Default::default()), - /// GameMod::HiddenTaiko(Default::default()), - /// GameMod::HardRockOsu(Default::default()), - /// ].into_iter().collect(); - /// - /// assert_eq!(mods.to_string(), "HDHRHD"); - /// - /// assert!(mods.remove_intermode(GameModIntermode::Hidden)); - /// assert_eq!(mods.to_string(), "HRHD"); - /// assert!(!mods.remove_intermode(GameModIntermode::DoubleTime)); - /// ``` - #[inline] - pub fn remove_intermode(&mut self, gamemod: M) -> bool - where - GameModIntermode: From, - { - self.inner - .remove(&GameModIntermode::from(gamemod)) - .is_some() - } - - /// Remove all mods contained in the iterator. - /// - /// # Example - /// ``` - /// use rosu_v2::prelude::{mods, GameMod, GameMods}; - /// - /// # let mut mods: GameMods = [ - /// # GameMod::HiddenOsu(Default::default()), - /// # GameMod::HardRockOsu(Default::default()), - /// # GameMod::WiggleOsu(Default::default()), - /// # GameMod::DoubleTimeOsu(Default::default()), - /// # GameMod::BarrelRollOsu(Default::default()), - /// # ].into_iter().collect(); - /// # /* - /// let mut mods: GameMods = mods!(Osu: HD HR WG DT BR); - /// # */ - /// - /// mods.remove_all([ - /// GameMod::HiddenOsu(Default::default()), - /// GameMod::EasyOsu(Default::default()) - /// ].iter()); - /// assert_eq!(mods.to_string(), "HRDTBRWG"); - /// - /// mods.remove_all(mods!(Osu: NF WG).iter()); - /// assert_eq!(mods.to_string(), "HRDTBR") - /// ``` - #[inline] - pub fn remove_all<'m, I>(&mut self, mods: I) - where - I: Iterator, - { - for gamemod in mods { - self.remove(gamemod); - } - } - - /// Remove all mods contained in the iterator. - /// - /// If the same gamemod is contained for multiple modes, each occurence of the gamemod - /// in the iterator will remove only one of the contained gamemods. - /// - /// # Example - /// ``` - /// use rosu_v2::prelude::{mods, GameMod, GameMods}; - /// - /// let mut mods: GameMods = [ - /// GameMod::HiddenOsu(Default::default()), - /// GameMod::HardRockOsu(Default::default()), - /// GameMod::HardRockCatch(Default::default()), - /// GameMod::WiggleOsu(Default::default()), - /// GameMod::DoubleTimeOsu(Default::default()), - /// GameMod::BarrelRollOsu(Default::default()), - /// ].into_iter().collect(); - /// - /// assert_eq!(mods.to_string(), "HDHRDTBRWGHR"); - /// mods.remove_all_intermode(mods!(HD HR WG)); - /// assert_eq!(mods.to_string(), "DTBRHR"); - /// ``` - #[inline] - pub fn remove_all_intermode(&mut self, mods: I) - where - I: IntoIterator, - GameModIntermode: From, - { - for gamemod in mods { - self.remove_intermode(gamemod); - } - } - - /// Returns an iterator over all mods that appear in both [`GameMods`]. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::GameMods; - /// - /// # use rosu_v2::prelude::GameMod; - /// # let hd = GameMods::from(GameMod::HiddenCatch(Default::default())); - /// # let hdhr: GameMods = [ - /// # GameMod::HiddenCatch(Default::default()), - /// # GameMod::HardRockCatch(Default::default()), - /// # ].into_iter().collect(); - /// # /* - /// let hd = mods!(Catch: HD); - /// let hdhr = mods!(Catch: HD HR); - /// # */ - /// let mut intersection = hd.intersection(&hdhr); - /// - /// assert_eq!(intersection.next(), Some(&GameMod::HiddenCatch(Default::default()))); - /// assert_eq!(intersection.next(), None); - /// ``` - // https://github.com/rust-lang/rust/blob/c1d3610ac1ddd1cd605479274047fd0a3f37d220/library/alloc/src/collections/btree/set.rs#L517 - pub fn intersection<'m>(&'m self, other: &'m GameMods) -> GameModsIntersection<'m> { - let (self_min, self_max) = if let (Some(self_min), Some(self_max)) = - (self.inner.first_key_value(), self.inner.last_key_value()) - { - (self_min, self_max) - } else { - return GameModsIntersection { - inner: IntersectionInner::Answer(None), - }; - }; - - let (other_min, other_max) = if let (Some(other_min), Some(other_max)) = - (other.inner.first_key_value(), other.inner.last_key_value()) - { - (other_min, other_max) - } else { - return GameModsIntersection { - inner: IntersectionInner::Answer(None), - }; - }; - - GameModsIntersection { - inner: match (self_min.0.cmp(other_max.0), self_max.0.cmp(other_min.0)) { - (Ordering::Greater, _) | (_, Ordering::Less) => IntersectionInner::Answer(None), - (Ordering::Equal, _) => IntersectionInner::Answer(Some(self_min.1)), - (_, Ordering::Equal) => IntersectionInner::Answer(Some(self_max.1)), - _ => IntersectionInner::new_stitch(self.inner.iter(), other.inner.iter()), - }, - } - } - - /// Check whether the two [`GameMods`] have any common mods. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::GameMods; - /// - /// # use rosu_v2::prelude::GameMod; - /// # let hd = GameMods::from(GameMod::HiddenCatch(Default::default())); - /// # let hr = GameMods::from(GameMod::HardRockCatch(Default::default())); - /// # let hdhr: GameMods = [ - /// # GameMod::HiddenCatch(Default::default()), - /// # GameMod::HardRockCatch(Default::default()), - /// # ].into_iter().collect(); - /// # /* - /// let hd = mods!(Catch: HD); - /// let hr = mods!(Catch: HR); - /// # */ - /// assert!(!hd.intersects(&hr)); - /// - /// # /* - /// let hdhr = mods!(Catch: HD HR); - /// # */ - /// assert!(hd.intersects(&hdhr)); - /// ``` - #[inline] - pub fn intersects(&self, other: &Self) -> bool { - self.intersection(other).next().is_some() - } - - /// The clock rate of the [`GameMods`]. - /// - /// Returns `None` if any contained [`GameMod`] has no single clock rate. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::GameMod; - /// - /// # let hd: rosu_v2::prelude::GameMods = [GameMod::HiddenOsu(Default::default())].into_iter().collect(); - /// # /* - /// let hd = mods!(Osu: HD); - /// # */ - /// assert_eq!(hd.clock_rate(), Some(1.0)); - /// - /// let mut hddt = hd; - /// hddt.insert(GameMod::DoubleTimeOsu(Default::default())); - /// assert_eq!(hddt.clock_rate(), Some(1.5)); - /// - /// let mut hddtwu = hddt; - /// hddtwu.insert(GameMod::WindUpOsu(Default::default())); - /// assert_eq!(hddtwu.clock_rate(), None); - /// ``` - pub fn clock_rate(&self) -> Option { - self.inner - .values() - .map(GameMod::clock_rate) - .try_fold(1.0, |clock_rate, next| next.map(|next| clock_rate * next)) - } - - /// Tries to create [`GameMods`] from a [`GameModsIntermode`]. - /// - /// Returns `None` if any contained [`GameModIntermode`] is unknown for the - /// given [`GameMode`]. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, GameMods, GameModsIntermode, GameMode}; - /// - /// let intermode: GameModsIntermode = mods!(DT FI); - /// let mods = GameMods::try_from_intermode(intermode.clone(), GameMode::Mania).unwrap(); - /// - /// // The FadeIn mod doesn't exist in Taiko - /// assert!(GameMods::try_from_intermode(intermode, GameMode::Taiko).is_none()); - /// ``` - pub fn try_from_intermode(mods: GameModsIntermode, mode: GameMode) -> Option { - mods.try_with_mode(mode) - } - - /// Create [`GameMods`] from a [`GameModsIntermode`]. - /// - /// Any contained [`GameModIntermode`] that's unknown for the given - /// [`GameMode`] will be replaced with `GameModIntermode::Unknown`. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::{mods, GameMods, GameModsIntermode, GameMode}; - /// - /// let intermode: GameModsIntermode = mods!(DT FI); - /// let mods = GameMods::from_intermode(intermode.clone(), GameMode::Mania); - /// - /// // The FadeIn mod doesn't exist in Taiko - /// let dt = GameMods::from_intermode(intermode, GameMode::Taiko); - /// ``` - pub fn from_intermode(mods: GameModsIntermode, mode: GameMode) -> Self { - mods.with_mode(mode) - } - - /// Returns an iterator over all contained mods. - /// - /// Note that the iterator will immediately yield `None` in case of "NoMod". - #[inline] - pub fn iter(&self) -> GameModsIter<'_> { - GameModsIter::new(self.inner.values()) - } - - /// Returns an iterator that allows modifying each contained mod. - /// - /// Note that the iterator will immediately yield `None` in case of "NoMod". - #[inline] - pub fn iter_mut(&mut self) -> GameModsIterMut<'_> { - GameModsIterMut::new(self.inner.values_mut()) - } - - /// Checks whether some contained mods exclude other contained mods. - /// - /// # Example - /// ```rust - /// use rosu_v2::prelude::GameMod; - /// - /// # let mut mods: rosu_v2::prelude::GameMods = [ - /// # GameMod::EasyOsu(Default::default()), - /// # ].into_iter().collect(); - /// # /* - /// let mut mods = mods!(Osu: EZ); - /// # */ - /// assert!(mods.is_valid()); - /// - /// mods.insert(GameMod::HardRockOsu(Default::default())); - /// assert!(!mods.is_valid()); - /// ``` - pub fn is_valid(&self) -> bool { - for gamemod in self.inner.values() { - for &acronym in gamemod.incompatible_mods().iter() { - if self.contains_acronym(acronym) { - return false; - } - } - } - - true - } - - /// Remove all mods that are excluded by other contained mods. - /// - /// # Example - /// ```rust - /// # let mut mods: rosu_v2::prelude::GameMods = [ - /// # rosu_v2::prelude::GameMod::EasyOsu(Default::default()), - /// # rosu_v2::prelude::GameMod::HardRockOsu(Default::default()) - /// # ].into_iter().collect(); - /// # /* - /// let mut mods = mods!(Osu: EZ HR); - /// # */ - /// assert_eq!(mods.to_string(), "EZHR"); - /// - /// mods.sanitize(); - /// assert_eq!(mods.to_string(), "EZ"); - /// ``` - pub fn sanitize(&mut self) { - 'outer: loop { - let mods = self.inner.values(); - - for gamemod in mods { - for &excluded in gamemod.incompatible_mods().iter() { - let intermode = GameModIntermode::from_acronym(excluded); - - if self.contains_intermode(intermode) { - self.inner.retain(|key, _| *key != intermode); - - continue 'outer; - } - } - } - - break; - } - } -} - -impl Debug for GameMods { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - f.debug_list().entries(self.inner.values()).finish() - } -} - -impl Display for GameMods { - #[inline] - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - if self.is_empty() { - f.write_str("NM") - } else { - for gamemod in self.iter() { - f.write_str(gamemod.acronym().as_str())?; - } - - Ok(()) - } - } -} - -impl From for GameMods { - #[inline] - fn from(gamemod: GameMod) -> Self { - let mut mods = Self::new(); - mods.insert(gamemod); - - mods - } -} - -impl IntoIterator for GameMods { - type Item = GameMod; - type IntoIter = IntoGameModsIter; - - /// Turns [`GameMods`] into an iterator over all contained mods. - /// - /// Note that the iterator will immediately yield `None` in case of "NoMod". - #[inline] - fn into_iter(self) -> Self::IntoIter { - IntoGameModsIter::new(self.inner.into_values()) - } -} - -impl FromIterator for GameMods { - fn from_iter>(iter: T) -> Self { - Self { - inner: iter - .into_iter() - .map(|gamemod| (GameModOrder::from(&gamemod), gamemod)) - .collect(), - } - } -} - -impl Extend for GameMods { - fn extend>(&mut self, iter: T) { - let iter = iter - .into_iter() - .map(|gamemod| (GameModOrder::from(&gamemod), gamemod)); - - self.inner.extend(iter); - } -} - -#[cfg(feature = "serialize")] -impl serde::Serialize for GameMods { - fn serialize(&self, s: S) -> Result { - use serde::ser::SerializeSeq; - - let mut s = s.serialize_seq(Some(self.inner.len()))?; - - for gamemod in self.inner.values() { - s.serialize_element(gamemod)?; - } - - s.end() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn insert_valid() { - let mut mods = GameMods::new(); - mods.insert(GameMod::HiddenOsu(Default::default())); - mods.insert(GameMod::HardRockOsu(Default::default())); - - assert_eq!(mods.len(), 2); - assert_eq!(mods.to_string(), "HDHR"); - } - - #[test] - fn contains() { - let mods: GameMods = [ - GameMod::HiddenOsu(Default::default()), - GameMod::HardRockOsu(Default::default()), - GameMod::NightcoreOsu(Default::default()), - ] - .into_iter() - .collect(); - assert!(mods.contains_intermode(GameModIntermode::Nightcore)); - assert!(mods.contains_intermode(GameModIntermode::Hidden)); - assert!(!mods.contains_intermode(GameModIntermode::DoubleTime)); - } - - #[test] - fn checked_bits() { - let mods: GameMods = [ - GameMod::HiddenOsu(Default::default()), - GameMod::TraceableOsu(Default::default()), - GameMod::DoubleTimeOsu(Default::default()), - ] - .into_iter() - .collect(); - - assert_eq!(mods.checked_bits(), None); - } - - #[test] - fn unchecked_bits() { - let mods: GameMods = [ - GameMod::TraceableOsu(Default::default()), - GameMod::DoubleTimeOsu(Default::default()), - GameMod::HiddenOsu(Default::default()), - ] - .into_iter() - .collect(); - - assert_eq!(mods.bits(), 72); - } - - #[test] - fn intersection() { - let a: GameMods = [ - GameMod::HiddenOsu(Default::default()), - GameMod::WindUpOsu(Default::default()), - GameMod::HardRockOsu(Default::default()), - ] - .into_iter() - .collect(); - - let b: GameMods = [ - GameMod::WindUpOsu(Default::default()), - GameMod::ClassicOsu(Default::default()), - GameMod::HardRockOsu(Default::default()), - ] - .into_iter() - .collect(); - - let mut iter = a.intersection(&b); - assert_eq!( - iter.next().map(GameMod::intermode), - Some(GameModIntermode::HardRock) - ); - assert_eq!( - iter.next().map(GameMod::intermode), - Some(GameModIntermode::WindUp) - ); - assert_eq!(iter.next(), None); - } - - #[test] - fn clock_rate_unaffected() { - let mods: GameMods = [ - GameMod::HiddenOsu(Default::default()), - GameMod::HardRockOsu(Default::default()), - GameMod::WiggleOsu(Default::default()), - ] - .into_iter() - .collect(); - - assert_eq!(mods.clock_rate(), Some(1.0)); - } - - #[test] - fn clock_rate_speed_change() { - let mut mods: GameMods = [GameMod::HardRockOsu(Default::default())] - .into_iter() - .collect(); - - mods.insert(GameMod::DoubleTimeOsu(DoubleTimeOsu { - speed_change: Some(1.25), - adjust_pitch: Some(false), - })); - assert_eq!(mods.clock_rate(), Some(1.25)); - } - - #[test] - fn clock_rate_variable() { - let mods: GameMods = [ - GameMod::HiddenOsu(Default::default()), - GameMod::WindUpOsu(Default::default()), - ] - .into_iter() - .collect(); - - assert_eq!(mods.clock_rate(), None); - } - - #[test] - fn sanitize() { - let mut mods: GameMods = [ - GameMod::BlindsOsu(Default::default()), - GameMod::FlashlightOsu(Default::default()), - GameMod::HiddenOsu(Default::default()), - GameMod::TraceableOsu(Default::default()), - ] - .into_iter() - .collect(); - - mods.sanitize(); - - assert_eq!(mods.to_string(), "HDFL"); - } -} diff --git a/rosu-v2/src/model/mods/mode_as_seed.rs b/rosu-v2/src/model/mods/mode_as_seed.rs deleted file mode 100644 index bed9608..0000000 --- a/rosu-v2/src/model/mods/mode_as_seed.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::{ - collections::BTreeMap, - fmt::{Formatter, Result as FmtResult}, - marker::PhantomData, -}; - -use serde::{ - de::{DeserializeSeed, Error as DeError, SeqAccess, Visitor}, - Deserializer, -}; - -use crate::prelude::GameMode; - -use super::{GameMod, GameModOrder, GameMods, GameModsIntermode}; - -/// Struct to pass a [`GameMode`] into some deserialization via [`DeserializeSeed`]. -pub struct ModeAsSeed { - pub(crate) mode: GameMode, - pub(crate) phantom: PhantomData, -} - -impl Clone for ModeAsSeed { - fn clone(&self) -> Self { - *self - } -} - -impl Copy for ModeAsSeed {} - -impl ModeAsSeed { - pub const fn new(mode: GameMode) -> Self { - Self { - mode, - phantom: PhantomData, - } - } - - pub const fn cast(self) -> ModeAsSeed { - ModeAsSeed::new(self.mode) - } -} - -impl<'de> Visitor<'de> for ModeAsSeed { - type Value = GameMods; - - fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { - f.write_str("a sequence of GameMod") - } - - fn visit_str(self, v: &str) -> Result { - let mods = v.parse::().map_err(DeError::custom)?; - - Ok(mods.with_mode(self.mode)) - } - - fn visit_u64(self, v: u64) -> Result { - let bits = u32::try_from(v).map_err(|_| DeError::custom("bitflags must fit in a u32"))?; - - Ok(GameModsIntermode::from_bits(bits).with_mode(self.mode)) - } - - fn visit_seq>(self, mut seq: A) -> Result { - let mut inner = BTreeMap::new(); - - while let Some(res) = seq.next_element_seed(self.cast::())? { - inner.insert(GameModOrder::from(&res), res); - } - - Ok(GameMods { inner }) - } -} - -impl<'de> DeserializeSeed<'de> for ModeAsSeed { - type Value = GameMods; - - fn deserialize>(self, d: D) -> Result { - d.deserialize_any(self) - } -} - -impl<'de> DeserializeSeed<'de> for ModeAsSeed { - type Value = GameMod; - - fn deserialize>(self, d: D) -> Result { - d.deserialize_any(self) - } -} diff --git a/rosu-v2/src/client/builder.rs b/src/client/builder.rs similarity index 100% rename from rosu-v2/src/client/builder.rs rename to src/client/builder.rs diff --git a/rosu-v2/src/client/mod.rs b/src/client/mod.rs similarity index 100% rename from rosu-v2/src/client/mod.rs rename to src/client/mod.rs diff --git a/rosu-v2/src/client/token.rs b/src/client/token.rs similarity index 100% rename from rosu-v2/src/client/token.rs rename to src/client/token.rs diff --git a/rosu-v2/src/error.rs b/src/error.rs similarity index 100% rename from rosu-v2/src/error.rs rename to src/error.rs diff --git a/rosu-v2/src/lib.rs b/src/lib.rs similarity index 93% rename from rosu-v2/src/lib.rs rename to src/lib.rs index a16ef8b..851233c 100644 --- a/rosu-v2/src/lib.rs +++ b/src/lib.rs @@ -140,6 +140,12 @@ pub use client::{Osu, OsuBuilder}; #[macro_use] extern crate log; +#[cfg(feature = "macros")] +extern crate rosu_mods; + +#[cfg(feature = "macros")] +pub use rosu_mods::mods; + /// `Result<_, OsuError>` pub type OsuResult = Result; @@ -149,14 +155,28 @@ pub mod prelude { client::Scope, error::OsuError, model::{ - beatmap::*, comments::*, event::*, forum::*, kudosu::*, matches::*, mods::*, news::*, - ranking::*, score::*, seasonal_backgrounds::*, user::*, wiki::*, GameMode, Grade, + beatmap::*, + comments::*, + event::*, + forum::*, + kudosu::*, + matches::*, + mods::{generated_mods::*, Acronym, GameMods, GameModsIntermode, GameModsLegacy}, + news::*, + ranking::*, + score::*, + seasonal_backgrounds::*, + user::*, + wiki::*, + GameMode, Grade, }, - mods, request::UserId, Osu, OsuBuilder, OsuResult, }; pub use hyper::StatusCode; pub use smallstr::SmallString; + + #[cfg(feature = "macros")] + pub use rosu_mods::mods; } diff --git a/rosu-v2/src/metrics.rs b/src/metrics.rs similarity index 100% rename from rosu-v2/src/metrics.rs rename to src/metrics.rs diff --git a/rosu-v2/src/model/beatmap.rs b/src/model/beatmap.rs similarity index 100% rename from rosu-v2/src/model/beatmap.rs rename to src/model/beatmap.rs diff --git a/rosu-v2/src/model/comments.rs b/src/model/comments.rs similarity index 100% rename from rosu-v2/src/model/comments.rs rename to src/model/comments.rs diff --git a/rosu-v2/src/model/event.rs b/src/model/event.rs similarity index 100% rename from rosu-v2/src/model/event.rs rename to src/model/event.rs diff --git a/rosu-v2/src/model/forum.rs b/src/model/forum.rs similarity index 100% rename from rosu-v2/src/model/forum.rs rename to src/model/forum.rs diff --git a/rosu-v2/src/model/grade.rs b/src/model/grade.rs similarity index 100% rename from rosu-v2/src/model/grade.rs rename to src/model/grade.rs diff --git a/rosu-v2/src/model/kudosu.rs b/src/model/kudosu.rs similarity index 100% rename from rosu-v2/src/model/kudosu.rs rename to src/model/kudosu.rs diff --git a/rosu-v2/src/model/matches.rs b/src/model/matches.rs similarity index 99% rename from rosu-v2/src/model/matches.rs rename to src/model/matches.rs index 5f21528..3d3f487 100644 --- a/rosu-v2/src/model/matches.rs +++ b/src/model/matches.rs @@ -1,12 +1,14 @@ use super::{ - beatmap::Beatmap, mods::GameMods, score::LegacyScoreStatistics, serde_util, user::User, + beatmap::Beatmap, + mods::{GameMods, GameModsIntermode}, + score::LegacyScoreStatistics, + serde_util, + user::User, GameMode, }; -use crate::{ - prelude::{GameModsIntermode, ModeAsSeed}, - Osu, OsuResult, -}; +use crate::{Osu, OsuResult}; +use rosu_mods::serde::GameModsSeed; use serde::{ de::{ DeserializeSeed, Deserializer, Error as DeError, Error, IgnoredAny, MapAccess, SeqAccess, @@ -344,7 +346,7 @@ impl<'de> Deserialize<'de> for MatchGame { let mut d = serde_json::Deserializer::from_str(game_raw.mods.get()); Ok(MatchGame { - mods: ModeAsSeed::::new(game_raw.mode) + mods: GameModsSeed::Mode(game_raw.mode) .deserialize(&mut d) .map_err(DeError::custom)?, game_id: game_raw.game_id, diff --git a/rosu-v2/src/model/mod.rs b/src/model/mod.rs similarity index 98% rename from rosu-v2/src/model/mod.rs rename to src/model/mod.rs index 15ae6e3..e14c252 100644 --- a/rosu-v2/src/model/mod.rs +++ b/src/model/mod.rs @@ -133,7 +133,6 @@ macro_rules! def_enum { } mod grade; -mod mode; mod serde_util; /// Beatmap(set) related types @@ -154,7 +153,7 @@ pub mod kudosu; /// Multiplayer match related types pub mod matches; -/// Game mods related types +/// Re-exports of `rosu-mods` pub mod mods; /// News related types @@ -176,7 +175,8 @@ pub mod user; pub mod wiki; pub use grade::Grade; -pub use mode::GameMode; + +pub use rosu_mods::GameMode; use std::marker::PhantomData; diff --git a/src/model/mods.rs b/src/model/mods.rs new file mode 100644 index 0000000..920e7ef --- /dev/null +++ b/src/model/mods.rs @@ -0,0 +1,4 @@ +pub use rosu_mods::{ + error, generated_mods, intersection, iter, mods, serde, Acronym, GameMod, GameModIntermode, + GameModKind, GameMods, GameModsIntermode, GameModsLegacy, +}; diff --git a/rosu-v2/src/model/news.rs b/src/model/news.rs similarity index 100% rename from rosu-v2/src/model/news.rs rename to src/model/news.rs diff --git a/rosu-v2/src/model/ranking.rs b/src/model/ranking.rs similarity index 100% rename from rosu-v2/src/model/ranking.rs rename to src/model/ranking.rs diff --git a/rosu-v2/src/model/score.rs b/src/model/score.rs similarity index 99% rename from rosu-v2/src/model/score.rs rename to src/model/score.rs index 0128772..ffa4d5d 100644 --- a/rosu-v2/src/model/score.rs +++ b/src/model/score.rs @@ -1,12 +1,13 @@ use super::{ beatmap::{BeatmapExtended, Beatmapset}, - mods::GameMods, + mods::{mods, GameMods}, serde_util, user::User, GameMode, Grade, }; -use crate::{mods, prelude::ModeAsSeed, request::GetUser, Osu}; +use crate::{request::GetUser, Osu}; +use rosu_mods::serde::GameModsSeed; use serde::{ de::{DeserializeSeed, Error as DeError, IgnoredAny}, Deserialize, Deserializer, @@ -168,7 +169,7 @@ impl<'de> Deserialize<'de> for Score { preserve: score_raw.preserve, processed: score_raw.processed, maximum_statistics: score_raw.maximum_statistics, - mods: ModeAsSeed::::new(score_raw.mode) + mods: GameModsSeed::Mode(score_raw.mode) .deserialize(&mut d) .map_err(DeError::custom)?, statistics: score_raw.statistics, diff --git a/rosu-v2/src/model/seasonal_backgrounds.rs b/src/model/seasonal_backgrounds.rs similarity index 100% rename from rosu-v2/src/model/seasonal_backgrounds.rs rename to src/model/seasonal_backgrounds.rs diff --git a/rosu-v2/src/model/serde_util.rs b/src/model/serde_util.rs similarity index 100% rename from rosu-v2/src/model/serde_util.rs rename to src/model/serde_util.rs diff --git a/rosu-v2/src/model/user.rs b/src/model/user.rs similarity index 100% rename from rosu-v2/src/model/user.rs rename to src/model/user.rs diff --git a/rosu-v2/src/model/wiki.rs b/src/model/wiki.rs similarity index 100% rename from rosu-v2/src/model/wiki.rs rename to src/model/wiki.rs diff --git a/rosu-v2/src/request/beatmap.rs b/src/request/beatmap.rs similarity index 100% rename from rosu-v2/src/request/beatmap.rs rename to src/request/beatmap.rs diff --git a/rosu-v2/src/request/comments.rs b/src/request/comments.rs similarity index 100% rename from rosu-v2/src/request/comments.rs rename to src/request/comments.rs diff --git a/rosu-v2/src/request/event.rs b/src/request/event.rs similarity index 100% rename from rosu-v2/src/request/event.rs rename to src/request/event.rs diff --git a/rosu-v2/src/request/forum.rs b/src/request/forum.rs similarity index 100% rename from rosu-v2/src/request/forum.rs rename to src/request/forum.rs diff --git a/rosu-v2/src/request/matches.rs b/src/request/matches.rs similarity index 100% rename from rosu-v2/src/request/matches.rs rename to src/request/matches.rs diff --git a/rosu-v2/src/request/mod.rs b/src/request/mod.rs similarity index 100% rename from rosu-v2/src/request/mod.rs rename to src/request/mod.rs diff --git a/rosu-v2/src/request/news.rs b/src/request/news.rs similarity index 100% rename from rosu-v2/src/request/news.rs rename to src/request/news.rs diff --git a/rosu-v2/src/request/ranking.rs b/src/request/ranking.rs similarity index 100% rename from rosu-v2/src/request/ranking.rs rename to src/request/ranking.rs diff --git a/rosu-v2/src/request/replay.rs b/src/request/replay.rs similarity index 100% rename from rosu-v2/src/request/replay.rs rename to src/request/replay.rs diff --git a/rosu-v2/src/request/seasonal_backgrounds.rs b/src/request/seasonal_backgrounds.rs similarity index 100% rename from rosu-v2/src/request/seasonal_backgrounds.rs rename to src/request/seasonal_backgrounds.rs diff --git a/rosu-v2/src/request/serialize.rs b/src/request/serialize.rs similarity index 100% rename from rosu-v2/src/request/serialize.rs rename to src/request/serialize.rs diff --git a/rosu-v2/src/request/user.rs b/src/request/user.rs similarity index 100% rename from rosu-v2/src/request/user.rs rename to src/request/user.rs diff --git a/rosu-v2/src/request/wiki.rs b/src/request/wiki.rs similarity index 100% rename from rosu-v2/src/request/wiki.rs rename to src/request/wiki.rs diff --git a/rosu-v2/src/routing.rs b/src/routing.rs similarity index 100% rename from rosu-v2/src/routing.rs rename to src/routing.rs diff --git a/rosu-v2/tests/requests.rs b/tests/requests.rs similarity index 99% rename from rosu-v2/tests/requests.rs rename to tests/requests.rs index e985082..dcef87a 100644 --- a/rosu-v2/tests/requests.rs +++ b/tests/requests.rs @@ -8,14 +8,13 @@ use std::{ use dotenv::dotenv; use eyre::{Result, WrapErr}; use once_cell::sync::OnceCell; -#[cfg(feature = "cache")] -use rosu_v2::mods; use rosu_v2::{ model::{ beatmap::{BeatmapsetSearchSort, RankStatus}, + event::EventSort, + mods::mods, GameMode, }, - prelude::EventSort, Osu, }; use tokio::sync::{Mutex, MutexGuard}; diff --git a/rosu-v2/tests/serde.rs b/tests/serde.rs similarity index 99% rename from rosu-v2/tests/serde.rs rename to tests/serde.rs index b1960d6..b2816ad 100644 --- a/rosu-v2/tests/serde.rs +++ b/tests/serde.rs @@ -3,8 +3,8 @@ extern crate rosu_v2; mod types { #![allow(unused)] - use rosu_v2::{mods, prelude::*}; - use serde::{de::DeserializeOwned, Serialize}; + use ::serde::{de::DeserializeOwned, Serialize}; + use rosu_v2::prelude::*; use std::{collections::HashMap, fmt::Debug}; use time::{Date, Duration, OffsetDateTime}; From 7c6fe2af428adb9a57ce72e6c96cd886b5b0eea5 Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Thu, 4 Jul 2024 12:53:56 +0200 Subject: [PATCH 2/3] use rosu-mods from crates.io --- Cargo.toml | 2 +- src/model/mods.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8283637..1bab748 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ log = { version = "0.4", default-features = false } hyper = { version = "0.14", default-features = false, features = ["client"] } hyper-rustls = { version = "0.24.1", default-features = false, features = ["http1", "http2", "native-tokio"] } itoa = { version = "1.0.9" } -rosu-mods = { path = "../rosu-mods", default-features = false, features = ["serde"] } +rosu-mods = { version = "0.1.0", features = ["serde"] } serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde_json = { version = "1.0", default-features = false, features = ["std", "raw_value"] } serde_urlencoded = { version = "0.7.1" } diff --git a/src/model/mods.rs b/src/model/mods.rs index 920e7ef..07d165d 100644 --- a/src/model/mods.rs +++ b/src/model/mods.rs @@ -1,4 +1,7 @@ pub use rosu_mods::{ - error, generated_mods, intersection, iter, mods, serde, Acronym, GameMod, GameModIntermode, + error, generated_mods, intersection, iter, serde, Acronym, GameMod, GameModIntermode, GameModKind, GameMods, GameModsIntermode, GameModsLegacy, }; + +#[cfg(feature = "macros")] +pub use rosu_mods::mods; From abf02136e47698925b399aaa9b25c851908ac6ca Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Thu, 4 Jul 2024 13:56:56 +0200 Subject: [PATCH 3/3] fixed no-default-features --- src/model/score.rs | 40 ++++++++++++++++++++++++++++------------ tests/requests.rs | 13 +++++++++++-- tests/serde.rs | 4 +++- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/model/score.rs b/src/model/score.rs index ffa4d5d..8ae3595 100644 --- a/src/model/score.rs +++ b/src/model/score.rs @@ -1,13 +1,13 @@ use super::{ beatmap::{BeatmapExtended, Beatmapset}, - mods::{mods, GameMods}, + mods::GameMods, serde_util, user::User, GameMode, Grade, }; use crate::{request::GetUser, Osu}; -use rosu_mods::serde::GameModsSeed; +use rosu_mods::{serde::GameModsSeed, GameModIntermode, GameModsIntermode}; use serde::{ de::{DeserializeSeed, Error as DeError, IgnoredAny}, Deserialize, Deserializer, @@ -530,9 +530,25 @@ pub struct UserAttributesPin { pub score_id: u64, } +fn hdfl() -> GameModsIntermode { + [GameModIntermode::Hidden, GameModIntermode::Flashlight] + .into_iter() + .collect() +} + +fn hdflfi() -> GameModsIntermode { + [ + GameModIntermode::Hidden, + GameModIntermode::Flashlight, + GameModIntermode::FadeIn, + ] + .into_iter() + .collect() +} + fn osu_grade(score: &Score, passed_objects: u32, accuracy: Option) -> Grade { if score.statistics.great == passed_objects { - return if score.mods.contains_any(mods!(HD FL)) { + return if score.mods.contains_any(hdfl()) { Grade::XH } else { Grade::X @@ -542,7 +558,7 @@ fn osu_grade(score: &Score, passed_objects: u32, accuracy: Option) -> Grade let accuracy = accuracy.unwrap_or_else(|| score.accuracy()); if accuracy >= 95.0 && score.statistics.miss == 0 { - if score.mods.contains_any(mods!(HD FL FI)) { + if score.mods.contains_any(hdflfi()) { Grade::SH } else { Grade::S @@ -572,7 +588,7 @@ fn mania_grade(score: &Score, passed_objects: u32, accuracy: Option) -> Gra fn osu_grade_legacy(score: &Score, passed_objects: u32) -> Grade { if score.statistics.great == passed_objects { - return if score.mods.contains_any(mods!(HD FL)) { + return if score.mods.contains_any(hdfl()) { Grade::XH } else { Grade::X @@ -585,7 +601,7 @@ fn osu_grade_legacy(score: &Score, passed_objects: u32) -> Grade { let ratio50 = stats.meh as f32 / passed_objects as f32; if ratio300 > 0.9 && ratio50 < 0.01 && stats.miss == 0 { - if score.mods.contains_any(mods!(HD FL)) { + if score.mods.contains_any(hdfl()) { Grade::SH } else { Grade::S @@ -603,7 +619,7 @@ fn osu_grade_legacy(score: &Score, passed_objects: u32) -> Grade { fn taiko_grade_legacy(score: &Score, passed_objects: u32) -> Grade { if score.statistics.great == passed_objects { - return if score.mods.contains_any(mods!(HD FL)) { + return if score.mods.contains_any(hdfl()) { Grade::XH } else { Grade::X @@ -614,7 +630,7 @@ fn taiko_grade_legacy(score: &Score, passed_objects: u32) -> Grade { let ratio300 = stats.great as f32 / passed_objects as f32; if ratio300 > 0.9 && stats.miss == 0 { - if score.mods.contains_any(mods!(HD FL)) { + if score.mods.contains_any(hdfl()) { Grade::SH } else { Grade::S @@ -634,13 +650,13 @@ fn catch_grade_legacy(score: &Score, accuracy: Option) -> Grade { let accuracy = accuracy.unwrap_or_else(|| score.accuracy()); if (100.0 - accuracy).abs() < std::f32::EPSILON { - if score.mods.contains_any(mods!(HD FL)) { + if score.mods.contains_any(hdfl()) { Grade::XH } else { Grade::X } } else if accuracy >= 98.0 { - if score.mods.contains_any(mods!(HD FL)) { + if score.mods.contains_any(hdfl()) { Grade::SH } else { Grade::S @@ -658,7 +674,7 @@ fn catch_grade_legacy(score: &Score, accuracy: Option) -> Grade { fn mania_grade_legacy(score: &Score, passed_objects: u32, accuracy: Option) -> Grade { if score.statistics.perfect == passed_objects { - return if score.mods.contains_any(mods!(HD FL FI)) { + return if score.mods.contains_any(hdflfi()) { Grade::XH } else { Grade::X @@ -668,7 +684,7 @@ fn mania_grade_legacy(score: &Score, passed_objects: u32, accuracy: Option) let accuracy = accuracy.unwrap_or_else(|| score.accuracy()); if accuracy >= 95.0 { - if score.mods.contains_any(mods!(HD FL FI)) { + if score.mods.contains_any(hdflfi()) { Grade::SH } else { Grade::S diff --git a/tests/requests.rs b/tests/requests.rs index dcef87a..790aced 100644 --- a/tests/requests.rs +++ b/tests/requests.rs @@ -12,7 +12,6 @@ use rosu_v2::{ model::{ beatmap::{BeatmapsetSearchSort, RankStatus}, event::EventSort, - mods::mods, GameMode, }, Osu, @@ -131,11 +130,21 @@ async fn beatmap_scores() -> Result<()> { #[cfg(feature = "cache")] #[tokio::test] async fn beatmap_user_score() -> Result<()> { + use rosu_v2::model::mods::{GameModIntermode, GameModsIntermode}; + + let mods = [ + GameModIntermode::Hidden, + GameModIntermode::HardRock, + GameModIntermode::HalfTime, + ] + .into_iter() + .collect::(); + let score = OSU .get() .await? .beatmap_user_score(ADESSO_BALLA, BADEWANNE3) - .mods(mods!(HD HR HT)) + .mods(mods) .await?; println!( diff --git a/tests/serde.rs b/tests/serde.rs index b2816ad..51b4c98 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -490,7 +490,9 @@ mod types { MatchScore { user_id: 123456, accuracy: 99.5, - mods: mods!(SV2 RX), + mods: [GameModIntermode::ScoreV2, GameModIntermode::Relax] + .into_iter() + .collect(), score: 12_345_678, max_combo: 1000, perfect: false,