1use std::fmt;
2
3#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
5#[cfg_attr(
6 feature = "rkyv",
7 repr(u8),
8 derive(rkyv::Portable, rkyv::bytecheck::CheckBytes),
9 bytecheck(crate = rkyv::bytecheck),
10)]
11pub enum GameMode {
12 #[default]
14 Osu = 0,
15 Taiko = 1,
17 Catch = 2,
19 Mania = 3,
21}
22
23impl GameMode {
24 pub const fn as_str(self) -> &'static str {
26 match self {
27 Self::Osu => "osu",
28 Self::Taiko => "taiko",
29 Self::Catch => "fruits",
30 Self::Mania => "mania",
31 }
32 }
33}
34
35impl From<u8> for GameMode {
36 fn from(mode: u8) -> Self {
37 match mode {
38 0 => GameMode::Osu,
39 1 => GameMode::Taiko,
40 2 => GameMode::Catch,
41 3 => GameMode::Mania,
42 _ => GameMode::Osu,
43 }
44 }
45}
46
47impl fmt::Display for GameMode {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 f.write_str(self.as_str())
50 }
51}
52
53#[cfg(feature = "serde")]
54#[cfg_attr(all(docsrs, not(doctest)), doc(cfg(feature = "serde")))]
55const _: () = {
56 use serde::{
57 de::{Deserialize, Deserializer, Error, Unexpected, Visitor},
58 ser::{Serialize, Serializer},
59 };
60
61 struct ModeVisitor;
62
63 impl Visitor<'_> for ModeVisitor {
64 type Value = GameMode;
65
66 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 f.write_str("a gamemode")
68 }
69
70 fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
71 let mode = match v {
72 "0" | "osu" | "osu!" => GameMode::Osu,
73 "1" | "taiko" | "tko" => GameMode::Taiko,
74 "2" | "catch" | "ctb" | "fruits" => GameMode::Catch,
75 "3" | "mania" | "mna" => GameMode::Mania,
76 _ => return Err(Error::invalid_value(Unexpected::Str(v), &Self)),
77 };
78
79 Ok(mode)
80 }
81
82 fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
83 match v {
84 0 => Ok(GameMode::Osu),
85 1 => Ok(GameMode::Taiko),
86 2 => Ok(GameMode::Catch),
87 3 => Ok(GameMode::Mania),
88 _ => Err(Error::invalid_value(Unexpected::Unsigned(v), &Self)),
89 }
90 }
91 }
92
93 impl<'de> Deserialize<'de> for GameMode {
94 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
95 d.deserialize_any(ModeVisitor)
96 }
97 }
98
99 impl Serialize for GameMode {
100 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
101 s.serialize_u8(*self as u8)
102 }
103 }
104};
105
106#[cfg(feature = "rkyv")]
107#[cfg_attr(all(docsrs, not(doctest)), doc(cfg(feature = "rkyv")))]
108const _: () = {
109 use rkyv::{rancor::Fallible, traits::NoUndef, Archive, Deserialize, Place, Serialize};
110
111 unsafe impl NoUndef for GameMode {}
112
113 impl Archive for GameMode {
114 type Archived = Self;
115 type Resolver = ();
116
117 fn resolve(&self, (): Self::Resolver, out: Place<Self::Archived>) {
118 out.write(*self);
119 }
120 }
121
122 impl<S: Fallible + ?Sized> Serialize<S> for GameMode {
123 fn serialize(&self, _: &mut S) -> Result<(), S::Error> {
124 Ok(())
125 }
126 }
127
128 impl<D: Fallible + ?Sized> Deserialize<Self, D> for GameMode {
129 fn deserialize(&self, _: &mut D) -> Result<Self, D::Error> {
130 Ok(*self)
131 }
132 }
133};