use crate::ir::{Field, StructLayout};
pub use crate::ir::optimal_order;
fn simulated_size(fields: &[&Field], struct_align: usize) -> usize {
let mut offset = 0usize;
for f in fields {
if f.align > 0 {
offset = offset.next_multiple_of(f.align);
}
offset += f.size;
}
if struct_align > 0 {
offset = offset.next_multiple_of(struct_align);
}
offset
}
pub fn reorder_savings(layout: &StructLayout) -> (usize, usize) {
if layout.fields.is_empty() {
return (layout.total_size, 0);
}
let ordered = optimal_order(layout);
let optimized = simulated_size(&ordered, layout.align);
let savings = layout.total_size.saturating_sub(optimized);
(optimized, savings)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ir::test_fixtures::{connection_layout, packed_layout};
#[test]
fn connection_saves_8_bytes() {
let (optimized, savings) = reorder_savings(&connection_layout());
assert_eq!(optimized, 16);
assert_eq!(savings, 8);
}
#[test]
fn packed_layout_saves_nothing() {
let (optimized, savings) = reorder_savings(&packed_layout());
assert_eq!(savings, 0);
assert_eq!(optimized, packed_layout().total_size);
}
#[test]
fn optimal_order_puts_largest_align_first() {
let layout = connection_layout();
let order = optimal_order(&layout);
assert_eq!(order[0].name, "timeout");
}
#[test]
fn simulated_size_matches_manual_calculation() {
let layout = connection_layout();
let ordered = optimal_order(&layout);
let sz = simulated_size(&ordered, layout.align);
assert_eq!(sz, 16);
}
}