use std::fmt;
#[derive(Debug, Clone, Default)]
pub struct CleanupStats {
pub types_removed: usize,
pub methods_removed: usize,
pub methodspecs_removed: usize,
pub fields_removed: usize,
pub attributes_removed: usize,
pub params_removed: usize,
pub standalonesigs_removed: usize,
pub genericparams_removed: usize,
pub genericparam_constraints_removed: usize,
pub interfaceimpls_removed: usize,
pub methodimpls_removed: usize,
pub methodsemantics_removed: usize,
pub nestedclasses_removed: usize,
pub classlayouts_removed: usize,
pub fieldrvas_removed: usize,
pub fieldlayouts_removed: usize,
pub fieldmarshals_removed: usize,
pub constants_removed: usize,
pub declsecurities_removed: usize,
pub implmaps_removed: usize,
pub eventmaps_removed: usize,
pub propertymaps_removed: usize,
pub typerefs_removed: usize,
pub memberrefs_removed: usize,
pub typespecs_removed: usize,
pub sections_excluded: usize,
pub strings_compacted: usize,
pub blobs_compacted: usize,
pub guids_compacted: usize,
}
impl CleanupStats {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn total_removed(&self) -> usize {
self.types_removed
+ self.methods_removed
+ self.methodspecs_removed
+ self.fields_removed
+ self.attributes_removed
+ self.params_removed
+ self.standalonesigs_removed
+ self.genericparams_removed
+ self.genericparam_constraints_removed
+ self.interfaceimpls_removed
+ self.methodimpls_removed
+ self.methodsemantics_removed
+ self.nestedclasses_removed
+ self.classlayouts_removed
+ self.fieldrvas_removed
+ self.fieldlayouts_removed
+ self.fieldmarshals_removed
+ self.constants_removed
+ self.declsecurities_removed
+ self.implmaps_removed
+ self.eventmaps_removed
+ self.propertymaps_removed
+ self.typerefs_removed
+ self.memberrefs_removed
+ self.typespecs_removed
}
#[must_use]
pub fn has_changes(&self) -> bool {
self.total_removed() > 0 || self.sections_excluded > 0 || self.heap_entries_compacted() > 0
}
#[must_use]
pub fn heap_entries_compacted(&self) -> usize {
self.strings_compacted + self.blobs_compacted + self.guids_compacted
}
#[must_use]
pub fn primary_removed(&self) -> usize {
self.types_removed + self.methods_removed + self.fields_removed
}
#[must_use]
pub fn orphans_removed(&self) -> usize {
self.total_removed() - self.primary_removed() - self.attributes_removed
}
pub fn merge(&mut self, other: &CleanupStats) {
self.types_removed += other.types_removed;
self.methods_removed += other.methods_removed;
self.methodspecs_removed += other.methodspecs_removed;
self.fields_removed += other.fields_removed;
self.attributes_removed += other.attributes_removed;
self.params_removed += other.params_removed;
self.standalonesigs_removed += other.standalonesigs_removed;
self.genericparams_removed += other.genericparams_removed;
self.genericparam_constraints_removed += other.genericparam_constraints_removed;
self.interfaceimpls_removed += other.interfaceimpls_removed;
self.methodimpls_removed += other.methodimpls_removed;
self.methodsemantics_removed += other.methodsemantics_removed;
self.nestedclasses_removed += other.nestedclasses_removed;
self.classlayouts_removed += other.classlayouts_removed;
self.fieldrvas_removed += other.fieldrvas_removed;
self.fieldlayouts_removed += other.fieldlayouts_removed;
self.fieldmarshals_removed += other.fieldmarshals_removed;
self.constants_removed += other.constants_removed;
self.declsecurities_removed += other.declsecurities_removed;
self.implmaps_removed += other.implmaps_removed;
self.eventmaps_removed += other.eventmaps_removed;
self.propertymaps_removed += other.propertymaps_removed;
self.typerefs_removed += other.typerefs_removed;
self.memberrefs_removed += other.memberrefs_removed;
self.typespecs_removed += other.typespecs_removed;
self.sections_excluded += other.sections_excluded;
self.strings_compacted += other.strings_compacted;
self.blobs_compacted += other.blobs_compacted;
self.guids_compacted += other.guids_compacted;
}
}
impl fmt::Display for CleanupStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.has_changes() {
return write!(f, "No changes");
}
let mut parts = Vec::new();
if self.types_removed > 0 {
parts.push(format!("{} types", self.types_removed));
}
if self.methods_removed > 0 {
parts.push(format!("{} methods", self.methods_removed));
}
if self.fields_removed > 0 {
parts.push(format!("{} fields", self.fields_removed));
}
if self.attributes_removed > 0 {
parts.push(format!("{} attributes", self.attributes_removed));
}
let orphans = self.orphans_removed();
if orphans > 0 {
parts.push(format!("{orphans} orphaned entries"));
}
if self.sections_excluded > 0 {
parts.push(format!("{} sections excluded", self.sections_excluded));
}
let heap_compacted = self.heap_entries_compacted();
if heap_compacted > 0 {
parts.push(format!("{heap_compacted} heap entries compacted"));
}
write!(f, "Removed: {}", parts.join(", "))
}
}
#[cfg(test)]
mod tests {
use crate::cilassembly::cleanup::CleanupStats;
#[test]
fn test_stats_default() {
let stats = CleanupStats::new();
assert_eq!(stats.total_removed(), 0);
assert!(!stats.has_changes());
}
#[test]
fn test_stats_counting() {
let mut stats = CleanupStats::new();
stats.types_removed = 5;
stats.methods_removed = 10;
stats.params_removed = 20;
assert_eq!(stats.primary_removed(), 15);
assert_eq!(stats.orphans_removed(), 20);
assert_eq!(stats.total_removed(), 35);
assert!(stats.has_changes());
}
#[test]
fn test_stats_merge() {
let mut stats1 = CleanupStats::new();
stats1.types_removed = 5;
let mut stats2 = CleanupStats::new();
stats2.methods_removed = 10;
stats1.merge(&stats2);
assert_eq!(stats1.types_removed, 5);
assert_eq!(stats1.methods_removed, 10);
}
#[test]
fn test_stats_display() {
let mut stats = CleanupStats::new();
stats.types_removed = 3;
stats.methods_removed = 7;
stats.params_removed = 15;
let display = stats.to_string();
assert!(display.contains("3 types"));
assert!(display.contains("7 methods"));
assert!(display.contains("orphaned"));
}
#[test]
fn test_stats_display_empty() {
let stats = CleanupStats::new();
assert_eq!(stats.to_string(), "No changes");
}
}