rosu-pp 4.0.1

Difficulty and performance calculation for osu!
Documentation
use crate::{
    taiko::difficulty::{
        object::{TaikoDifficultyObject, TaikoDifficultyObjects},
        utils::interval_grouping::group_by_interval,
    },
    util::sync::RefCount,
};

use super::data::{
    same_patterns_grouped_hit_objects::SamePatternsGroupedHitObjects,
    same_rhythm_hit_object_grouping::SameRhythmHitObjectGrouping,
};

pub struct RhythmDifficultyPreprocessor;

impl RhythmDifficultyPreprocessor {
    pub fn process_and_assign(hit_objects: &TaikoDifficultyObjects) {
        let rhythm_groups = create_same_rhythm_grouped_hit_objects(&hit_objects.note_objects);

        for rhythm_group in rhythm_groups.iter() {
            for hit_object in rhythm_group.get().hit_objects.iter() {
                if let Some(hit_object) = hit_object.upgrade() {
                    hit_object
                        .get_mut()
                        .rhythm_data
                        .same_rhythm_grouped_hit_objects = Some(RefCount::clone(rhythm_group));
                }
            }
        }

        let pattern_groups = create_same_pattern_grouped_hit_objects(&rhythm_groups);

        for pattern_group in pattern_groups {
            for group in pattern_group.get().upgraded_groups() {
                for hit_object in group.get().upgraded_hit_objects() {
                    hit_object
                        .get_mut()
                        .rhythm_data
                        .same_patterns_grouped_hit_objects = Some(RefCount::clone(&pattern_group));
                }
            }
        }
    }
}

fn create_same_rhythm_grouped_hit_objects(
    hit_objects: &[RefCount<TaikoDifficultyObject>],
) -> Vec<RefCount<SameRhythmHitObjectGrouping>> {
    let mut rhythm_groups = Vec::new();

    for grouped in group_by_interval(hit_objects) {
        rhythm_groups.push(RefCount::new(SameRhythmHitObjectGrouping::new(
            rhythm_groups.last().map(RefCount::downgrade),
            grouped,
        )));
    }

    rhythm_groups
}

fn create_same_pattern_grouped_hit_objects(
    rhythm_groups: &[RefCount<SameRhythmHitObjectGrouping>],
) -> impl Iterator<Item = RefCount<SamePatternsGroupedHitObjects>> + use<'_> {
    group_by_interval(rhythm_groups).scan(None, |prev, grouped| {
        let curr = RefCount::new(SamePatternsGroupedHitObjects::new(prev.take(), grouped));
        *prev = Some(curr.downgrade());

        Some(curr)
    })
}