#[derive(Clone, Debug, Default)]
#[expect(
clippy::struct_field_names,
reason = "field names are descriptive and clear"
)]
pub(crate) struct OperationMetrics {
pub(crate) total_bytes_allocated: u64,
pub(crate) total_allocations_count: u64,
pub(crate) total_iterations: u64,
}
impl OperationMetrics {
pub(crate) fn add_iterations(&mut self, bytes_delta: u64, count_delta: u64, iterations: u64) {
let total_bytes = bytes_delta
.checked_mul(iterations)
.expect("bytes * iterations overflows u64 - this indicates an unrealistic scenario");
let total_count = count_delta
.checked_mul(iterations)
.expect("count * iterations overflows u64 - this indicates an unrealistic scenario");
self.total_bytes_allocated = self
.total_bytes_allocated
.checked_add(total_bytes)
.expect("total bytes allocated overflows u64 - this indicates an unrealistic scenario");
self.total_allocations_count = self
.total_allocations_count
.checked_add(total_count)
.expect(
"total allocations count overflows u64 - this indicates an unrealistic scenario",
);
self.total_iterations = self.total_iterations.checked_add(iterations).expect(
"total iterations count overflows u64 - this indicates an unrealistic scenario",
);
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
#[test]
fn operation_metrics_default_values() {
let metrics = OperationMetrics::default();
assert_eq!(metrics.total_bytes_allocated, 0);
assert_eq!(metrics.total_allocations_count, 0);
assert_eq!(metrics.total_iterations, 0);
}
#[test]
fn operation_metrics_add_iterations_basic() {
let mut metrics = OperationMetrics::default();
metrics.add_iterations(100, 5, 5);
assert_eq!(metrics.total_iterations, 5);
assert_eq!(metrics.total_bytes_allocated, 500);
assert_eq!(metrics.total_allocations_count, 25);
}
#[test]
fn operation_metrics_add_iterations_zero_iterations() {
let mut metrics = OperationMetrics::default();
metrics.add_iterations(100, 2, 0);
assert_eq!(metrics.total_iterations, 0);
assert_eq!(metrics.total_bytes_allocated, 0);
assert_eq!(metrics.total_allocations_count, 0);
}
#[test]
fn operation_metrics_add_iterations_zero_allocation() {
let mut metrics = OperationMetrics::default();
metrics.add_iterations(0, 0, 1000);
assert_eq!(metrics.total_iterations, 1000);
assert_eq!(metrics.total_bytes_allocated, 0);
assert_eq!(metrics.total_allocations_count, 0);
}
#[test]
fn operation_metrics_add_iterations_accumulates() {
let mut metrics = OperationMetrics::default();
metrics.add_iterations(100, 2, 2); metrics.add_iterations(200, 3, 3);
assert_eq!(metrics.total_iterations, 5);
assert_eq!(metrics.total_bytes_allocated, 800);
assert_eq!(metrics.total_allocations_count, 13);
}
}