struct_audit/analysis/
padding.rs

1use crate::types::{LayoutMetrics, PaddingHole, StructLayout};
2
3pub fn analyze_layout(layout: &mut StructLayout, cache_line_size: u32) {
4    let mut padding_holes = Vec::new();
5    let mut useful_size: u64 = 0;
6    let mut current_offset: u64 = 0;
7    let mut last_member_name: Option<String> = None;
8    let mut partial = false;
9
10    for member in &layout.members {
11        let Some(member_offset) = member.offset else {
12            partial = true;
13            last_member_name = Some(member.name.clone());
14            continue;
15        };
16
17        let Some(member_size) = member.size else {
18            partial = true;
19            last_member_name = Some(member.name.clone());
20            continue;
21        };
22
23        if member_offset > current_offset {
24            let gap_size = member_offset - current_offset;
25            padding_holes.push(PaddingHole {
26                offset: current_offset,
27                size: gap_size,
28                after_member: last_member_name.clone(),
29            });
30        }
31
32        useful_size += member_size;
33        current_offset = current_offset.max(member_offset + member_size);
34        last_member_name = Some(member.name.clone());
35    }
36
37    if current_offset < layout.size {
38        let tail_padding = layout.size - current_offset;
39        padding_holes.push(PaddingHole {
40            offset: current_offset,
41            size: tail_padding,
42            after_member: last_member_name,
43        });
44    }
45
46    let padding_bytes: u64 = padding_holes.iter().map(|h| h.size).sum();
47    let padding_percentage =
48        if layout.size > 0 { (padding_bytes as f64 / layout.size as f64) * 100.0 } else { 0.0 };
49
50    let cache_line_size_u64 = cache_line_size as u64;
51    let cache_lines_spanned =
52        if layout.size > 0 { layout.size.div_ceil(cache_line_size_u64) as u32 } else { 0 };
53
54    let total_cache_bytes = cache_lines_spanned as u64 * cache_line_size_u64;
55    let cache_line_density = if total_cache_bytes > 0 {
56        (useful_size as f64 / total_cache_bytes as f64) * 100.0
57    } else {
58        0.0
59    };
60
61    layout.metrics = LayoutMetrics {
62        total_size: layout.size,
63        useful_size,
64        padding_bytes,
65        padding_percentage,
66        cache_lines_spanned,
67        cache_line_density,
68        padding_holes,
69        partial,
70    };
71}