rosu_pp/model/beatmap/attributes/attribute.rs
1/// A beatmap attribute.
2///
3/// It contains either:
4/// - the default value (5.0)
5/// - a value taken from a [`Beatmap`] or mutated default value
6/// - a user-given value that may be adjusted
7/// - a user-given *fixed* value that will stay as-is
8///
9/// [`Beatmap`]: crate::Beatmap
10#[derive(Copy, Clone, Debug, Default, PartialEq)]
11pub enum BeatmapAttribute {
12 /// No value has been set.
13 ///
14 /// Will be treated as the default value (5.0).
15 #[default]
16 None,
17 /// Variable value taken from a [`Beatmap`] or mutated default value that
18 /// may be overriden and adjusted based on mods and clock rate.
19 ///
20 /// [`Beatmap`]: crate::Beatmap
21 Value(f32),
22 /// Given by the user and may not be overriden by custom mod values.
23 ///
24 /// Mods and clock rate may *adjust* the value, though.
25 ///
26 /// # Example
27 /// Mods include `DifficultyAdjust` which sets AR to 9.5 but the user
28 /// specified AR to be 9.7. In this case, the user's value is should take
29 /// precedence.
30 Given(f32),
31 /// Represents a final value that should not be adjusted based on mods or
32 /// clock rate.
33 Fixed(f32),
34}
35
36impl BeatmapAttribute {
37 /// The default value for a `BeatmapAttribute`.
38 pub const DEFAULT: f32 = 5.0;
39
40 /// Overwrites `self` with `other` if `other` is not `None`.
41 #[must_use]
42 pub const fn overwrite(self, other: Self) -> Self {
43 if let Self::None = other { self } else { other }
44 }
45
46 /// Mutates the `Value` and `Given` variants.
47 pub fn try_mutate(&mut self, f: impl Fn(&mut f32)) {
48 if let Self::None = self {
49 *self = Self::Value(Self::DEFAULT);
50 }
51
52 if let Self::Value(value) | Self::Given(value) = self {
53 f(value);
54 }
55 }
56
57 /// Sets the `Value` variant only.
58 pub const fn try_set(&mut self, value: f32) {
59 match self {
60 Self::None => *self = Self::Value(value),
61 Self::Value(old) => *old = value,
62 _ => {}
63 }
64 }
65
66 /// Applies `f` onto the `Value` and `Given` variants and `default` onto the
67 /// `Fixed` variant.
68 pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
69 where
70 D: FnOnce(f32) -> U,
71 F: FnOnce(f32) -> U,
72 {
73 match self {
74 Self::None => f(Self::DEFAULT),
75 Self::Value(value) | Self::Given(value) => f(value),
76 Self::Fixed(fixed) => default(fixed),
77 }
78 }
79
80 pub const fn get_raw(self) -> f32 {
81 match self {
82 Self::None => Self::DEFAULT,
83 Self::Value(value) | Self::Given(value) | Self::Fixed(value) => value,
84 }
85 }
86}