removed Copy from score states but added Eq + PartiqlEq
This commit is contained in:
@@ -2,12 +2,11 @@ use crate::{Beatmap, FruitsPP};
|
||||
|
||||
use super::{FruitsGradualDifficultyAttributes, FruitsPerformanceAttributes};
|
||||
|
||||
// TODO: Benchmark if Copy is faster than Clone
|
||||
/// Aggregation for a score's current state i.e. what was the
|
||||
/// maximum combo so far and what are the current hitresults.
|
||||
///
|
||||
/// This struct is used for [`FruitsGradualPerformanceAttributes`].
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct FruitsScoreState {
|
||||
/// Maximum combo that the score has had so far.
|
||||
/// **Not** the maximum possible combo of the map so far.
|
||||
@@ -70,10 +69,10 @@ impl FruitsScoreState {
|
||||
/// state.max_combo += 1;
|
||||
///
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
/// }
|
||||
///
|
||||
/// // Then comes a miss.
|
||||
@@ -81,10 +80,10 @@ impl FruitsScoreState {
|
||||
/// // the next few objects because the combo is reset.
|
||||
/// state.misses += 1;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
///
|
||||
/// // The next 10 objects will be a mixture of fruits and droplets.
|
||||
/// // Notice how tiny droplets from sliders do not count as hit objects
|
||||
@@ -94,19 +93,19 @@ impl FruitsScoreState {
|
||||
/// state.n_droplets += 6;
|
||||
/// state.n_tiny_droplets += 12;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_n_objects(state, 10).unwrap();
|
||||
/// let performance = gradual_perf.process_next_n_objects(state.clone(), 10).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state, 10);
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state.clone(), 10);
|
||||
///
|
||||
/// // Now comes another fruit. Note that the max combo gets incremented again.
|
||||
/// state.n_fruits += 1;
|
||||
/// state.max_combo += 1;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
///
|
||||
/// // Skip to the end
|
||||
/// # /*
|
||||
@@ -116,10 +115,10 @@ impl FruitsScoreState {
|
||||
/// state.n_tiny_droplets = ...
|
||||
/// state.n_tiny_droplet_misses = ...
|
||||
/// state.misses = ...
|
||||
/// let final_performance = gradual_perf.process_next_n_objects(state, usize::MAX).unwrap();
|
||||
/// let final_performance = gradual_perf.process_next_n_objects(state.clone(), usize::MAX).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state, usize::MAX);
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state.clone(), usize::MAX);
|
||||
///
|
||||
/// // Once the final performance was calculated,
|
||||
/// // attempting to process further objects will return `None`.
|
||||
@@ -202,7 +201,9 @@ mod tests {
|
||||
let mut gradual = FruitsGradualPerformanceAttributes::new(&map, mods);
|
||||
let state = FruitsScoreState::default();
|
||||
|
||||
assert!(gradual.process_next_n_objects(state, usize::MAX).is_some());
|
||||
assert!(gradual
|
||||
.process_next_n_objects(state.clone(), usize::MAX)
|
||||
.is_some());
|
||||
assert!(gradual.process_next_object(state).is_none());
|
||||
}
|
||||
|
||||
@@ -217,14 +218,14 @@ mod tests {
|
||||
let mut gradual2 = FruitsGradualPerformanceAttributes::new(&map, mods);
|
||||
|
||||
for _ in 0..20 {
|
||||
let _ = gradual1.process_next_object(state);
|
||||
let _ = gradual2.process_next_object(state);
|
||||
let _ = gradual1.process_next_object(state.clone());
|
||||
let _ = gradual2.process_next_object(state.clone());
|
||||
}
|
||||
|
||||
let n = 80;
|
||||
|
||||
for _ in 1..n {
|
||||
let _ = gradual1.process_next_object(state);
|
||||
let _ = gradual1.process_next_object(state.clone());
|
||||
}
|
||||
|
||||
// TODO
|
||||
@@ -237,7 +238,7 @@ mod tests {
|
||||
misses: 0,
|
||||
};
|
||||
|
||||
let next = gradual1.process_next_object(state);
|
||||
let next = gradual1.process_next_object(state.clone());
|
||||
let next_n = gradual2.process_next_n_objects(state, n);
|
||||
|
||||
assert_eq!(next_n, next);
|
||||
|
||||
+11
-21
@@ -112,17 +112,13 @@ impl Iterator for GradualDifficultyAttributes<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Benchmark if Copy is faster than Clone
|
||||
/// Aggregation for a score's current state i.e. what wa
|
||||
/// the maximum combo so far, what are the current
|
||||
/// hitresults and what is the current score.
|
||||
///
|
||||
/// This struct is used for [`GradualPerformanceAttributes`].
|
||||
///
|
||||
/// Depending on your mode features, some fields might be optimized out.
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct ScoreState {
|
||||
#[cfg(any(feature = "osu", feature = "fruits", feature = "taiko"))]
|
||||
/// Maximum combo that the score has had so far.
|
||||
/// **Not** the maximum possible combo of the map so far.
|
||||
///
|
||||
@@ -130,32 +126,26 @@ pub struct ScoreState {
|
||||
///
|
||||
/// Irrelevant for osu!mania.
|
||||
pub max_combo: usize,
|
||||
#[cfg(feature = "fruits")]
|
||||
/// Amount of current katus (tiny droplet misses for osu!ctb).
|
||||
///
|
||||
/// Only relevant for osu!ctb.
|
||||
pub n_katu: usize,
|
||||
#[cfg(any(feature = "osu", feature = "fruits", feature = "taiko"))]
|
||||
/// Amount of current 300s (fruits for osu!ctb).
|
||||
///
|
||||
/// Irrelevant for osu!mania.
|
||||
pub n300: usize,
|
||||
#[cfg(any(feature = "osu", feature = "fruits", feature = "taiko"))]
|
||||
/// Amount of current 100s (droplets for osu!ctb).
|
||||
///
|
||||
/// Irrelevant for osu!mania.
|
||||
pub n100: usize,
|
||||
#[cfg(any(feature = "osu", feature = "fruits"))]
|
||||
/// Amount of current 50s (tiny droplets for osu!ctb).
|
||||
///
|
||||
/// Irrelevant for osu!taiko and osu!mania.
|
||||
pub n50: usize,
|
||||
#[cfg(any(feature = "osu", feature = "fruits", feature = "taiko"))]
|
||||
/// Amount of current misses (fruits + droplets for osu!ctb).
|
||||
///
|
||||
/// Irrelevant for osu!mania.
|
||||
pub misses: usize,
|
||||
#[cfg(feature = "mania")]
|
||||
/// The current score.
|
||||
///
|
||||
/// Only relevant for osu!mania.
|
||||
@@ -255,10 +245,10 @@ impl From<ScoreState> for TaikoScoreState {
|
||||
/// state.score += 123;
|
||||
///
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
/// }
|
||||
///
|
||||
/// // Then comes a miss.
|
||||
@@ -266,10 +256,10 @@ impl From<ScoreState> for TaikoScoreState {
|
||||
/// // the next few objects because the combo is reset.
|
||||
/// state.misses += 1;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
///
|
||||
/// // The next 10 objects will be a mixture of 300s, 100s, and 50s.
|
||||
/// // Notice how all 10 objects will be processed in one go.
|
||||
@@ -279,30 +269,30 @@ impl From<ScoreState> for TaikoScoreState {
|
||||
/// state.score += 987;
|
||||
/// // Don't forget state.n_katu
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_n_objects(state, 10).unwrap();
|
||||
/// let performance = gradual_perf.process_next_n_objects(state.clone(), 10).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state, 10);
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state.clone(), 10);
|
||||
///
|
||||
/// // Now comes another 300. Note that the max combo gets incremented again.
|
||||
/// state.n300 += 1;
|
||||
/// state.max_combo += 1;
|
||||
/// state.score += 123;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
///
|
||||
/// // Skip to the end
|
||||
/// # /*
|
||||
/// state.max_combo = ...
|
||||
/// state.n300 = ...
|
||||
/// ...
|
||||
/// let final_performance = gradual_perf.process_next_n_objects(state, usize::MAX).unwrap();
|
||||
/// let final_performance = gradual_perf.process_next_n_objects(state.clone(), usize::MAX).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state, usize::MAX);
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state.clone(), usize::MAX);
|
||||
///
|
||||
/// // Once the final performance was calculated,
|
||||
/// // attempting to process further objects will return `None`.
|
||||
|
||||
@@ -2,12 +2,11 @@ use crate::{Beatmap, OsuPP};
|
||||
|
||||
use super::{OsuGradualDifficultyAttributes, OsuPerformanceAttributes};
|
||||
|
||||
// TODO: Benchmark if Copy is faster than Clone
|
||||
/// Aggregation for a score's current state i.e. what was the
|
||||
/// maximum combo so far and what are the current hitresults.
|
||||
///
|
||||
/// This struct is used for [`OsuGradualPerformanceAttributes`].
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct OsuScoreState {
|
||||
/// Maximum combo that the score has had so far.
|
||||
/// **Not** the maximum possible combo of the map so far.
|
||||
@@ -63,10 +62,10 @@ impl OsuScoreState {
|
||||
/// state.max_combo += 1;
|
||||
///
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
/// }
|
||||
///
|
||||
/// // Then comes a miss.
|
||||
@@ -74,10 +73,10 @@ impl OsuScoreState {
|
||||
/// // the next few objects because the combo is reset.
|
||||
/// state.misses += 1;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
///
|
||||
/// // The next 10 objects will be a mixture of 300s, 100s, and 50s.
|
||||
/// // Notice how all 10 objects will be processed in one go.
|
||||
@@ -85,19 +84,19 @@ impl OsuScoreState {
|
||||
/// state.n100 += 7;
|
||||
/// state.n50 += 1;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_n_objects(state, 10).unwrap();
|
||||
/// let performance = gradual_perf.process_next_n_objects(state.clone(), 10).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state, 10);
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state.clone(), 10);
|
||||
///
|
||||
/// // Now comes another 300. Note that the max combo gets incremented again.
|
||||
/// state.n300 += 1;
|
||||
/// state.max_combo += 1;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
///
|
||||
/// // Skip to the end
|
||||
/// # /*
|
||||
@@ -106,10 +105,10 @@ impl OsuScoreState {
|
||||
/// state.n100 = ...
|
||||
/// state.n50 = ...
|
||||
/// state.misses = ...
|
||||
/// let final_performance = gradual_perf.process_next_n_objects(state, usize::MAX).unwrap();
|
||||
/// let final_performance = gradual_perf.process_next_n_objects(state.clone(), usize::MAX).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state, usize::MAX);
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state.clone(), usize::MAX);
|
||||
///
|
||||
/// // Once the final performance was calculated,
|
||||
/// // attempting to process further objects will return `None`.
|
||||
@@ -181,7 +180,9 @@ mod tests {
|
||||
let mut gradual = OsuGradualPerformanceAttributes::new(&map, mods);
|
||||
let state = OsuScoreState::default();
|
||||
|
||||
assert!(gradual.process_next_n_objects(state, usize::MAX).is_some());
|
||||
assert!(gradual
|
||||
.process_next_n_objects(state.clone(), usize::MAX)
|
||||
.is_some());
|
||||
assert!(gradual.process_next_object(state).is_none());
|
||||
}
|
||||
|
||||
@@ -196,14 +197,14 @@ mod tests {
|
||||
let mut gradual2 = OsuGradualPerformanceAttributes::new(&map, mods);
|
||||
|
||||
for _ in 0..20 {
|
||||
let _ = gradual1.process_next_object(state);
|
||||
let _ = gradual2.process_next_object(state);
|
||||
let _ = gradual1.process_next_object(state.clone());
|
||||
let _ = gradual2.process_next_object(state.clone());
|
||||
}
|
||||
|
||||
let n = 80;
|
||||
|
||||
for _ in 1..n {
|
||||
let _ = gradual1.process_next_object(state);
|
||||
let _ = gradual1.process_next_object(state.clone());
|
||||
}
|
||||
|
||||
let state = OsuScoreState {
|
||||
@@ -214,7 +215,7 @@ mod tests {
|
||||
misses: 2,
|
||||
};
|
||||
|
||||
let next = gradual1.process_next_object(state);
|
||||
let next = gradual1.process_next_object(state.clone());
|
||||
let next_n = gradual2.process_next_n_objects(state, n);
|
||||
|
||||
assert_eq!(next_n, next);
|
||||
|
||||
@@ -2,12 +2,11 @@ use crate::{Beatmap, TaikoPP};
|
||||
|
||||
use super::{TaikoGradualDifficultyAttributes, TaikoPerformanceAttributes};
|
||||
|
||||
// TODO: Benchmark if Copy is faster than Clone
|
||||
/// Aggregation for a score's current state i.e. what was the
|
||||
/// maximum combo so far and what are the current hitresults.
|
||||
///
|
||||
/// This struct is used for [`TaikoGradualPerformanceAttributes`].
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct TaikoScoreState {
|
||||
/// Maximum combo that the score has had so far.
|
||||
/// **Not** the maximum possible combo of the map so far.
|
||||
@@ -61,10 +60,10 @@ impl TaikoScoreState {
|
||||
/// state.max_combo += 1;
|
||||
///
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
/// }
|
||||
///
|
||||
/// // Then comes a miss.
|
||||
@@ -72,29 +71,29 @@ impl TaikoScoreState {
|
||||
/// // the next few objects because the combo is reset.
|
||||
/// state.misses += 1;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
///
|
||||
/// // The next 10 objects will be a mixture of 300s and 100s.
|
||||
/// // Notice how all 10 objects will be processed in one go.
|
||||
/// state.n300 += 3;
|
||||
/// state.n100 += 7;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_n_objects(state, 10).unwrap();
|
||||
/// let performance = gradual_perf.process_next_n_objects(state.clone(), 10).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state, 10);
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state.clone(), 10);
|
||||
///
|
||||
/// // Now comes another 300. Note that the max combo gets incremented again.
|
||||
/// state.n300 += 1;
|
||||
/// state.max_combo += 1;
|
||||
/// # /*
|
||||
/// let performance = gradual_perf.process_next_object(state).unwrap();
|
||||
/// let performance = gradual_perf.process_next_object(state.clone()).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_object(state);
|
||||
/// # let _ = gradual_perf.process_next_object(state.clone());
|
||||
///
|
||||
/// // Skip to the end
|
||||
/// # /*
|
||||
@@ -102,10 +101,10 @@ impl TaikoScoreState {
|
||||
/// state.n300 = ...
|
||||
/// state.n100 = ...
|
||||
/// state.misses = ...
|
||||
/// let final_performance = gradual_perf.process_next_n_objects(state, usize::MAX).unwrap();
|
||||
/// let final_performance = gradual_perf.process_next_n_objects(state.clone(), usize::MAX).unwrap();
|
||||
/// println!("PP: {}", performance.pp);
|
||||
/// # */
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state, usize::MAX);
|
||||
/// # let _ = gradual_perf.process_next_n_objects(state.clone(), usize::MAX);
|
||||
///
|
||||
/// // Once the final performance was calculated,
|
||||
/// // attempting to process further objects will return `None`.
|
||||
@@ -178,7 +177,9 @@ mod tests {
|
||||
let mut gradual = TaikoGradualPerformanceAttributes::new(&map, mods);
|
||||
let state = TaikoScoreState::default();
|
||||
|
||||
assert!(gradual.process_next_n_objects(state, usize::MAX).is_some());
|
||||
assert!(gradual
|
||||
.process_next_n_objects(state.clone(), usize::MAX)
|
||||
.is_some());
|
||||
assert!(gradual.process_next_object(state).is_none());
|
||||
}
|
||||
|
||||
@@ -193,14 +194,14 @@ mod tests {
|
||||
let mut gradual2 = TaikoGradualPerformanceAttributes::new(&map, mods);
|
||||
|
||||
for _ in 0..50 {
|
||||
let _ = gradual1.process_next_object(state);
|
||||
let _ = gradual2.process_next_object(state);
|
||||
let _ = gradual1.process_next_object(state.clone());
|
||||
let _ = gradual2.process_next_object(state.clone());
|
||||
}
|
||||
|
||||
let n = 200;
|
||||
|
||||
for _ in 1..n {
|
||||
let _ = gradual1.process_next_object(state);
|
||||
let _ = gradual1.process_next_object(state.clone());
|
||||
}
|
||||
|
||||
let state = TaikoScoreState {
|
||||
@@ -210,7 +211,7 @@ mod tests {
|
||||
misses: 6,
|
||||
};
|
||||
|
||||
let next = gradual1.process_next_object(state);
|
||||
let next = gradual1.process_next_object(state.clone());
|
||||
let next_n = gradual2.process_next_n_objects(state, n);
|
||||
|
||||
assert_eq!(next_n, next);
|
||||
|
||||
Reference in New Issue
Block a user