From dbdda55065945207a960d591d900a8dfc0088290 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 26 Sep 2024 23:47:03 -0600 Subject: [PATCH] Add Report::split A hack for supporting games that build all versions at once. --- objdiff-core/src/bindings/report.rs | 66 +++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/objdiff-core/src/bindings/report.rs b/objdiff-core/src/bindings/report.rs index 94557c7..f8e4962 100644 --- a/objdiff-core/src/bindings/report.rs +++ b/objdiff-core/src/bindings/report.rs @@ -117,6 +117,72 @@ impl Report { measures.calc_matched_percent(); } } + + /// Split the report into multiple reports based on progress categories. + /// Assumes progress categories are in the format `version`, `version.category`. + /// This is a hack for projects that generate all versions in a single report. + pub fn split(self) -> Vec<(String, Report)> { + let mut reports = Vec::new(); + // Map units to Option to allow taking ownership + let mut units = self.units.into_iter().map(Some).collect::>(); + for category in &self.categories { + if category.id.contains(".") { + // Skip subcategories + continue; + } + fn is_sub_category(id: &str, parent: &str, sep: char) -> bool { + id.starts_with(parent) + && id.get(parent.len()..).map_or(false, |s| s.starts_with(sep)) + } + let mut sub_categories = self + .categories + .iter() + .filter(|c| is_sub_category(&c.id, &category.id, '.')) + .cloned() + .collect::>(); + // Remove category prefix + for sub_category in &mut sub_categories { + sub_category.id = sub_category.id[category.id.len() + 1..].to_string(); + } + let mut sub_units = units + .iter_mut() + .filter_map(|opt| { + let unit = opt.as_mut()?; + let metadata = unit.metadata.as_ref()?; + if metadata.progress_categories.contains(&category.id) { + opt.take() + } else { + None + } + }) + .collect::>(); + for sub_unit in &mut sub_units { + // Remove leading version/ from unit name + if let Some(name) = + sub_unit.name.strip_prefix(&category.id).and_then(|s| s.strip_prefix('/')) + { + sub_unit.name = name.to_string(); + } + // Filter progress categories + let Some(metadata) = sub_unit.metadata.as_mut() else { + continue; + }; + metadata.progress_categories = metadata + .progress_categories + .iter() + .filter(|c| is_sub_category(c, &category.id, '.')) + .map(|c| c[category.id.len() + 1..].to_string()) + .collect(); + } + reports.push((category.id.clone(), Report { + measures: category.measures, + units: sub_units, + version: self.version, + categories: sub_categories, + })); + } + reports + } } impl Measures {